common: compile libcompat as C++
authorSimon Marchi <simon.marchi@efficios.com>
Fri, 3 Sep 2021 21:31:29 +0000 (17:31 -0400)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Wed, 17 Nov 2021 23:58:46 +0000 (18:58 -0500)
I got errors like these for programs that use libcompat (usually through
libcommon), but are still linked with gcc, rather than g++:

  CCLD     filter-grammar-test
/usr/bin/ld: ./.libs/libcommon.a(directory-handle.o):(.data.rel.local.DW.ref.__gxx_personality_v0[DW.ref.__gxx_personality_v0]+0x0): undefined reference to `_
_gxx_personality_v0'

Automake still links them with gcc, because they don't contain any C++
source directly. Fix that by changing them to be C++ source.

Change-Id: I3eeca3d9af8940795b69f48d306f282ae0b08589
Signed-off-by: Simon Marchi <simon.marchi@efficios.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
61 files changed:
include/lttng/action/rate-policy-internal.h
include/lttng/event-expr-internal.h
include/lttng/kernel-probe-internal.h
include/lttng/log-level-rule-internal.h
src/common/Makefile.am
src/common/compat/Makefile.am
src/common/compat/compat-fcntl.c [deleted file]
src/common/compat/compat-fcntl.cpp [new file with mode: 0644]
src/common/compat/directory-handle.c [deleted file]
src/common/compat/directory-handle.cpp [new file with mode: 0644]
src/common/compat/fcntl.h
src/common/compat/poll.c [deleted file]
src/common/compat/poll.cpp [new file with mode: 0644]
src/common/filter-grammar-test.c [deleted file]
src/common/filter-grammar-test.cpp [new file with mode: 0644]
tests/unit/Makefile.am
tests/unit/ini_config/Makefile.am
tests/unit/ini_config/ini_config.c [deleted file]
tests/unit/ini_config/ini_config.cpp [new file with mode: 0644]
tests/unit/test_action.c [deleted file]
tests/unit/test_action.cpp [new file with mode: 0644]
tests/unit/test_buffer_view.c [deleted file]
tests/unit/test_buffer_view.cpp [new file with mode: 0644]
tests/unit/test_condition.c [deleted file]
tests/unit/test_condition.cpp [new file with mode: 0644]
tests/unit/test_directory_handle.c [deleted file]
tests/unit/test_directory_handle.cpp [new file with mode: 0644]
tests/unit/test_event_expr_to_bytecode.c [deleted file]
tests/unit/test_event_expr_to_bytecode.cpp [new file with mode: 0644]
tests/unit/test_event_rule.c [deleted file]
tests/unit/test_event_rule.cpp [new file with mode: 0644]
tests/unit/test_fd_tracker.c [deleted file]
tests/unit/test_fd_tracker.cpp [new file with mode: 0644]
tests/unit/test_kernel_probe.c [deleted file]
tests/unit/test_kernel_probe.cpp [new file with mode: 0644]
tests/unit/test_log_level_rule.c [deleted file]
tests/unit/test_log_level_rule.cpp [new file with mode: 0644]
tests/unit/test_notification.c [deleted file]
tests/unit/test_notification.cpp [new file with mode: 0644]
tests/unit/test_payload.c [deleted file]
tests/unit/test_payload.cpp [new file with mode: 0644]
tests/unit/test_rate_policy.c [deleted file]
tests/unit/test_rate_policy.cpp [new file with mode: 0644]
tests/unit/test_string_utils.c [deleted file]
tests/unit/test_string_utils.cpp [new file with mode: 0644]
tests/unit/test_unix_socket.c [deleted file]
tests/unit/test_unix_socket.cpp [new file with mode: 0644]
tests/unit/test_uri.c [deleted file]
tests/unit/test_uri.cpp [new file with mode: 0644]
tests/unit/test_utils_compat_poll.c [deleted file]
tests/unit/test_utils_compat_poll.cpp [new file with mode: 0644]
tests/unit/test_utils_compat_pthread.c [deleted file]
tests/unit/test_utils_compat_pthread.cpp [new file with mode: 0644]
tests/unit/test_utils_expand_path.c [deleted file]
tests/unit/test_utils_expand_path.cpp [new file with mode: 0644]
tests/unit/test_utils_parse_size_suffix.c [deleted file]
tests/unit/test_utils_parse_size_suffix.cpp [new file with mode: 0644]
tests/unit/test_utils_parse_time_suffix.c [deleted file]
tests/unit/test_utils_parse_time_suffix.cpp [new file with mode: 0644]
tests/unit/test_uuid.c [deleted file]
tests/unit/test_uuid.cpp [new file with mode: 0644]

index c04cabcb23511352f57083455b40a84c4c4b9fb1..2f8267a31ad9b47ad23be80cf597f78d4f19045d 100644 (file)
 #include <common/macros.h>
 #include <common/payload-view.h>
 #include <lttng/action/rate-policy.h>
+#include <lttng/lttng-error.h>
 #include <stdbool.h>
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 struct mi_writer;
 
 int lttng_rate_policy_serialize(struct lttng_rate_policy *rate_policy,
@@ -37,4 +42,8 @@ enum lttng_error_code lttng_rate_policy_mi_serialize(
                const struct lttng_rate_policy *policy,
                struct mi_writer *writer);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* LTTNG_RATE_POLICY */
index 469fd17bbf32f685ff05f42760aae07eaaf6c82c..d40f2fa017f272ec12961e49cda9e59d69a7dd2d 100644 (file)
 #include <common/macros.h>
 #include <lttng/event-expr.h>
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 struct lttng_bytecode;
 struct mi_writer;
 
@@ -64,4 +68,8 @@ enum lttng_error_code lttng_event_expr_mi_serialize(
                const struct lttng_event_expr *expression,
                struct mi_writer *writer);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* LTTNG_EVENT_EXPR_INTERNAL_H */
index 06c3d7c7e77e097c2cc7b23b36f733a969252297..e0b94749ef777fb297e09492061d29d59fc72e69 100644 (file)
 #include <common/fd-handle.h>
 #include <common/macros.h>
 #include <lttng/kernel-probe.h>
+#include <lttng/lttng-error.h>
 #include <stdbool.h>
 #include <stdint.h>
 #include <sys/types.h>
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 struct lttng_payload;
 struct lttng_payload_view;
 struct lttng_dynamic_buffer;
@@ -106,4 +111,8 @@ enum lttng_error_code lttng_kernel_probe_location_mi_serialize(
                const struct lttng_kernel_probe_location *location,
                struct mi_writer *writer);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* LTTNG_KERNEL_PROBE_INTERNAL_H */
index b02afafe0d8d563c86bfeca1c192df1c42a5d029..26abaa862e317759772dfd88cc5a3157afd3f77b 100644 (file)
@@ -17,6 +17,7 @@
 #include <common/payload.h>
 #include <lttng/event.h>
 #include <lttng/log-level-rule.h>
+#include <lttng/lttng-error.h>
 
 #ifdef __cplusplus
 extern "C" {
index 5d1904d9c084ecc4fb7359b5eb9c787d150e15c6..cb8ac7b10ab2190a98adca2bf62dd2e4a6885d61 100644 (file)
@@ -175,7 +175,7 @@ noinst_HEADERS = \
        utils.h
 
 noinst_PROGRAMS = filter-grammar-test
-filter_grammar_test_SOURCES = filter-grammar-test.c
+filter_grammar_test_SOURCES = filter-grammar-test.cpp
 filter_grammar_test_LDADD = \
        libcommon.la
 
index a8f2c10019afe07e076854a1f24ff2b366c27b24..0499b356824694fb3aab0e13abff5d98affca013 100644 (file)
@@ -2,8 +2,23 @@
 
 noinst_LTLIBRARIES = libcompat.la
 
-libcompat_la_SOURCES = poll.c poll.h fcntl.h endian.h mman.h dirent.h \
-               socket.h compat-fcntl.c tid.h \
-               getenv.h string.h paths.h pthread.h netdb.h \
-               time.h directory-handle.h directory-handle.c path.h \
-               errno.h
+libcompat_la_SOURCES = \
+        compat-fcntl.cpp \
+        directory-handle.cpp \
+        directory-handle.h \
+        dirent.h \
+        endian.h \
+        errno.h \
+        fcntl.h \
+        getenv.h \
+        mman.h \
+        netdb.h \
+        path.h \
+        paths.h \
+        poll.cpp \
+        poll.h \
+        pthread.h \
+        socket.h \
+        string.h \
+        tid.h \
+        time.h
diff --git a/src/common/compat/compat-fcntl.c b/src/common/compat/compat-fcntl.c
deleted file mode 100644 (file)
index bc014d6..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2011 David Goulet <dgoulet@efficios.com>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-#define _LGPL_SOURCE
-#include <common/compat/fcntl.h>
-#include <common/macros.h>
-#include <unistd.h>
-
-#ifdef __linux__
-
-int compat_sync_file_range(int fd, off64_t offset, off64_t nbytes,
-               unsigned int flags)
-{
-#ifdef HAVE_SYNC_FILE_RANGE
-       return sync_file_range(fd, offset, nbytes, flags);
-#else
-       return fdatasync(fd);
-#endif
-}
-
-#endif /* __linux__ */
diff --git a/src/common/compat/compat-fcntl.cpp b/src/common/compat/compat-fcntl.cpp
new file mode 100644 (file)
index 0000000..bc014d6
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2011 David Goulet <dgoulet@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#define _LGPL_SOURCE
+#include <common/compat/fcntl.h>
+#include <common/macros.h>
+#include <unistd.h>
+
+#ifdef __linux__
+
+int compat_sync_file_range(int fd, off64_t offset, off64_t nbytes,
+               unsigned int flags)
+{
+#ifdef HAVE_SYNC_FILE_RANGE
+       return sync_file_range(fd, offset, nbytes, flags);
+#else
+       return fdatasync(fd);
+#endif
+}
+
+#endif /* __linux__ */
diff --git a/src/common/compat/directory-handle.c b/src/common/compat/directory-handle.c
deleted file mode 100644 (file)
index 9b98e04..0000000
+++ /dev/null
@@ -1,1386 +0,0 @@
-/*
- * Copyright (C) 2019 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-#include <common/compat/directory-handle.h>
-#include <common/error.h>
-#include <common/macros.h>
-#include <common/runas.h>
-#include <common/credentials.h>
-#include <lttng/constant.h>
-#include <common/dynamic-array.h>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <dirent.h>
-
-/*
- * This compatibility layer shares a common "base" that is implemented
- * in terms of an internal API. This file contains two implementations
- * of the internal API below.
- */
-static
-int lttng_directory_handle_mkdir(
-               const struct lttng_directory_handle *handle,
-               const char *path, mode_t mode);
-static
-int _run_as_mkdir(const struct lttng_directory_handle *handle, const char *path,
-               mode_t mode, uid_t uid, gid_t gid);
-static
-int _run_as_mkdir_recursive(const struct lttng_directory_handle *handle,
-               const char *path, mode_t mode, uid_t uid, gid_t gid);
-static
-int lttng_directory_handle_open(const struct lttng_directory_handle *handle,
-               const char *filename, int flags, mode_t mode);
-static
-int _run_as_open(const struct lttng_directory_handle *handle,
-               const char *filename,
-               int flags, mode_t mode, uid_t uid, gid_t gid);
-static
-int lttng_directory_handle_unlink(
-               const struct lttng_directory_handle *handle,
-               const char *filename);
-static
-int _run_as_unlink(const struct lttng_directory_handle *handle,
-               const char *filename, uid_t uid, gid_t gid);
-static
-int _lttng_directory_handle_rename(
-               const struct lttng_directory_handle *old_handle,
-               const char *old_name,
-               const struct lttng_directory_handle *new_handle,
-               const char *new_name);
-static
-int _run_as_rename(const struct lttng_directory_handle *old_handle,
-               const char *old_name,
-               const struct lttng_directory_handle *new_handle,
-               const char *new_name, uid_t uid, gid_t gid);
-static
-DIR *lttng_directory_handle_opendir(const struct lttng_directory_handle *handle,
-               const char *path);
-static
-int lttng_directory_handle_rmdir(
-               const struct lttng_directory_handle *handle, const char *name);
-static
-int _run_as_rmdir(const struct lttng_directory_handle *handle,
-               const char *name, uid_t uid, gid_t gid);
-static
-int _run_as_rmdir_recursive(
-               const struct lttng_directory_handle *handle, const char *name,
-               uid_t uid, gid_t gid, int flags);
-static
-void lttng_directory_handle_invalidate(struct lttng_directory_handle *handle);
-static
-void lttng_directory_handle_release(struct urcu_ref *ref);
-
-#ifdef HAVE_DIRFD
-
-/*
- * Special inode number reserved to represent the "current working directory".
- * ino_t is spec'ed as being an unsigned integral type.
- */
-#define RESERVED_AT_FDCWD_INO                      \
-       ({                                         \
-               uint64_t reserved_val;             \
-               switch (sizeof(ino_t)) {           \
-               case 4:                            \
-                       reserved_val = UINT32_MAX; \
-                       break;                     \
-               case 8:                            \
-                       reserved_val = UINT64_MAX; \
-                       break;                     \
-               default:                           \
-                       abort();                   \
-               }                                  \
-               (ino_t) reserved_val;              \
-       })
-
-struct lttng_directory_handle *lttng_directory_handle_create(const char *path)
-{
-       const struct lttng_directory_handle cwd_handle = {
-               .dirfd = AT_FDCWD,
-       };
-
-       /* Open a handle to the CWD if NULL is passed. */
-       return lttng_directory_handle_create_from_handle(path, &cwd_handle);
-}
-
-struct lttng_directory_handle *lttng_directory_handle_create_from_handle(
-               const char *path,
-               const struct lttng_directory_handle *ref_handle)
-{
-       int dirfd;
-       struct lttng_directory_handle *handle = NULL;
-
-       if (!path) {
-               handle = lttng_directory_handle_copy(ref_handle);
-               goto end;
-       }
-       if (!*path) {
-               ERR("Failed to initialize directory handle: provided path is an empty string");
-               goto end;
-       }
-
-       dirfd = openat(ref_handle->dirfd, path, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
-       if (dirfd == -1) {
-               PERROR("Failed to initialize directory handle to \"%s\"", path);
-               goto end;
-       }
-
-       handle = lttng_directory_handle_create_from_dirfd(dirfd);
-       if (!handle) {
-               goto error_close;
-       }
-end:
-       return handle;
-error_close:
-       if (close(dirfd)) {
-               PERROR("Failed to close directory file descriptor");
-       }
-       return NULL;
-}
-
-struct lttng_directory_handle *lttng_directory_handle_create_from_dirfd(
-               int dirfd)
-{
-       int ret;
-       struct lttng_directory_handle *handle = zmalloc(sizeof(*handle));
-       struct stat stat_buf;
-
-       if (!handle) {
-               goto end;
-       }
-
-       if (dirfd != AT_FDCWD) {
-               ret = fstat(dirfd, &stat_buf);
-               if (ret) {
-                       PERROR("Failed to fstat directory file descriptor %i", dirfd);
-                       lttng_directory_handle_release(&handle->ref);
-                       handle = NULL;
-                       goto end;
-               }
-       } else {
-               handle->directory_inode = RESERVED_AT_FDCWD_INO;
-       }
-       handle->dirfd = dirfd;
-       urcu_ref_init(&handle->ref);
-end:
-       return handle;
-}
-
-static
-void lttng_directory_handle_release(struct urcu_ref *ref)
-{
-       int ret;
-       struct lttng_directory_handle *handle =
-                       container_of(ref, struct lttng_directory_handle, ref);
-
-       if (handle->destroy_cb) {
-               handle->destroy_cb(handle, handle->destroy_cb_data);
-       }
-
-       if (handle->dirfd == AT_FDCWD || handle->dirfd == -1) {
-               goto end;
-       }
-       ret = close(handle->dirfd);
-       if (ret == -1) {
-               PERROR("Failed to close directory file descriptor of directory handle");
-       }
-end:
-       lttng_directory_handle_invalidate(handle);
-       free(handle);
-}
-
-struct lttng_directory_handle *lttng_directory_handle_copy(
-               const struct lttng_directory_handle *handle)
-{
-       struct lttng_directory_handle *new_handle = NULL;
-
-       if (handle->dirfd == AT_FDCWD) {
-               new_handle = lttng_directory_handle_create_from_dirfd(AT_FDCWD);
-       } else {
-               const int new_dirfd = dup(handle->dirfd);
-
-               if (new_dirfd == -1) {
-                       PERROR("Failed to duplicate directory file descriptor of directory handle");
-                       goto end;
-               }
-               new_handle = lttng_directory_handle_create_from_dirfd(
-                               new_dirfd);
-               if (!new_handle && close(new_dirfd)) {
-                       PERROR("Failed to close directory file descriptor of directory handle");
-               }
-       }
-end:
-       return new_handle;
-}
-
-bool lttng_directory_handle_equals(const struct lttng_directory_handle *lhs,
-               const struct lttng_directory_handle *rhs)
-{
-       return lhs->directory_inode == rhs->directory_inode;
-}
-
-static
-void lttng_directory_handle_invalidate(struct lttng_directory_handle *handle)
-{
-       handle->dirfd = -1;
-}
-
-int lttng_directory_handle_stat(const struct lttng_directory_handle *handle,
-               const char *path, struct stat *st)
-{
-       return fstatat(handle->dirfd, path, st, 0);
-}
-
-bool lttng_directory_handle_uses_fd(
-               const struct lttng_directory_handle *handle)
-{
-       return handle->dirfd != AT_FDCWD;
-}
-
-static
-int lttng_directory_handle_mkdir(
-               const struct lttng_directory_handle *handle,
-               const char *path, mode_t mode)
-{
-       return mkdirat(handle->dirfd, path, mode);
-}
-
-static
-int lttng_directory_handle_open(const struct lttng_directory_handle *handle,
-               const char *filename, int flags, mode_t mode)
-{
-       return openat(handle->dirfd, filename, flags, mode);
-}
-
-static
-int _run_as_open(const struct lttng_directory_handle *handle,
-               const char *filename,
-               int flags, mode_t mode, uid_t uid, gid_t gid)
-{
-       return run_as_openat(handle->dirfd, filename, flags, mode, uid, gid);
-}
-
-static
-int _run_as_unlink(const struct lttng_directory_handle *handle,
-               const char *filename, uid_t uid, gid_t gid)
-{
-       return run_as_unlinkat(handle->dirfd, filename, uid, gid);
-}
-
-static
-int lttng_directory_handle_unlink(
-               const struct lttng_directory_handle *handle,
-               const char *filename)
-{
-       return unlinkat(handle->dirfd, filename, 0);
-}
-
-static
-int _run_as_mkdir(const struct lttng_directory_handle *handle,
-               const char *path, mode_t mode, uid_t uid, gid_t gid)
-{
-       return run_as_mkdirat(handle->dirfd, path, mode, uid, gid);
-}
-
-static
-int _run_as_mkdir_recursive(const struct lttng_directory_handle *handle,
-               const char *path, mode_t mode, uid_t uid, gid_t gid)
-{
-       return run_as_mkdirat_recursive(handle->dirfd, path, mode, uid, gid);
-}
-
-static
-int _lttng_directory_handle_rename(
-               const struct lttng_directory_handle *old_handle,
-               const char *old_name,
-               const struct lttng_directory_handle *new_handle,
-               const char *new_name)
-{
-       return renameat(old_handle->dirfd, old_name,
-                       new_handle->dirfd, new_name);
-}
-
-static
-int _run_as_rename(const struct lttng_directory_handle *old_handle,
-               const char *old_name,
-               const struct lttng_directory_handle *new_handle,
-               const char *new_name, uid_t uid, gid_t gid)
-{
-       return run_as_renameat(old_handle->dirfd, old_name, new_handle->dirfd,
-                       new_name, uid, gid);
-}
-
-static
-DIR *lttng_directory_handle_opendir(const struct lttng_directory_handle *handle,
-               const char *path)
-{
-       DIR *dir_stream = NULL;
-       int fd = openat(handle->dirfd, path, O_RDONLY);
-
-       if (fd < 0) {
-               goto end;
-       }
-
-       dir_stream = fdopendir(fd);
-       if (!dir_stream) {
-               int ret;
-
-               PERROR("Failed to open directory stream");
-               ret = close(fd);
-               if (ret) {
-                       PERROR("Failed to close file descriptor to %s", path);
-               }
-               goto end;
-       }
-
-end:
-       return dir_stream;
-}
-
-static
-int lttng_directory_handle_rmdir(
-               const struct lttng_directory_handle *handle, const char *name)
-{
-       int ret = unlinkat(handle->dirfd, name, AT_REMOVEDIR);
-       if (ret) {
-               PERROR("Failed to remove directory `%s`", name);
-       }
-
-       return ret;
-}
-
-static
-int _run_as_rmdir(const struct lttng_directory_handle *handle,
-               const char *name, uid_t uid, gid_t gid)
-{
-       return run_as_rmdirat(handle->dirfd, name, uid, gid);
-}
-
-static
-int _run_as_rmdir_recursive(
-               const struct lttng_directory_handle *handle, const char *name,
-               uid_t uid, gid_t gid, int flags)
-{
-       return run_as_rmdirat_recursive(handle->dirfd, name, uid, gid, flags);
-}
-
-#else /* HAVE_DIRFD */
-
-static
-int get_full_path(const struct lttng_directory_handle *handle,
-               const char *subdirectory, char *fullpath, size_t size)
-{
-       int ret;
-       const bool subdirectory_is_absolute =
-                       subdirectory && *subdirectory == '/';
-       const char * const base = subdirectory_is_absolute ?
-                       subdirectory : handle->base_path;
-       const char * const end = subdirectory && !subdirectory_is_absolute ?
-                       subdirectory : NULL;
-       const size_t base_len = strlen(base);
-       const size_t end_len = end ? strlen(end) : 0;
-       const bool add_separator_slash = end && base[base_len - 1] != '/';
-       const bool add_trailing_slash = end && end[end_len - 1] != '/';
-
-       ret = snprintf(fullpath, size, "%s%s%s%s",
-                       base,
-                       add_separator_slash ? "/" : "",
-                       end ? end : "",
-                       add_trailing_slash ? "/" : "");
-       if (ret == -1 || ret >= size) {
-               ERR("Failed to format subdirectory from directory handle");
-               ret = -1;
-               goto end;
-       }
-       ret = 0;
-end:
-       return ret;
-}
-
-static
-struct lttng_directory_handle *_lttng_directory_handle_create(char *path)
-{
-       struct lttng_directory_handle *handle = zmalloc(sizeof(*handle));
-
-       if (!handle) {
-               goto end;
-       }
-       urcu_ref_init(&handle->ref);
-       handle->base_path = path;
-end:
-       return handle;
-}
-
-struct lttng_directory_handle *lttng_directory_handle_create(
-               const char *path)
-{
-       int ret;
-       const char *cwd = "";
-       size_t cwd_len, path_len;
-       char cwd_buf[LTTNG_PATH_MAX] = {};
-       char handle_buf[LTTNG_PATH_MAX] = {};
-       struct lttng_directory_handle *new_handle = NULL;
-       bool add_cwd_slash = false, add_trailing_slash = false;
-       const struct lttng_directory_handle cwd_handle = {
-               .base_path = handle_buf,
-       };
-
-       path_len = path ? strlen(path) : 0;
-       add_trailing_slash = path && path[path_len - 1] != '/';
-       if (!path || (path && *path != '/')) {
-               cwd = getcwd(cwd_buf, sizeof(cwd_buf));
-               if (!cwd) {
-                       PERROR("Failed to initialize directory handle, can't get current working directory");
-                       ret = -1;
-                       goto end;
-               }
-               cwd_len = strlen(cwd);
-               if (cwd_len == 0) {
-                       ERR("Failed to initialize directory handle, current working directory path has a length of 0");
-                       ret = -1;
-                       goto end;
-               }
-               add_cwd_slash = cwd[cwd_len - 1] != '/';
-       }
-
-       ret = snprintf(handle_buf, sizeof(handle_buf), "%s%s%s%s",
-                       cwd,
-                       add_cwd_slash ? "/" : "",
-                       path ? : "",
-                       add_trailing_slash ? "/" : "");
-       if (ret == -1 || ret >= LTTNG_PATH_MAX) {
-               ERR("Failed to initialize directory handle, failed to format directory path");
-               goto end;
-       }
-
-       new_handle = lttng_directory_handle_create_from_handle(path, &cwd_handle);
-end:
-       return new_handle;
-}
-
-struct lttng_directory_handle *lttng_directory_handle_create_from_handle(
-               const char *path,
-               const struct lttng_directory_handle *ref_handle)
-{
-       int ret;
-       size_t path_len, handle_path_len;
-       bool add_trailing_slash;
-       struct stat stat_buf;
-       struct lttng_directory_handle *new_handle = NULL;
-       char *new_path = NULL;
-
-       LTTNG_ASSERT(ref_handle && ref_handle->base_path);
-
-       ret = lttng_directory_handle_stat(ref_handle, path, &stat_buf);
-       if (ret == -1) {
-               PERROR("Failed to create directory handle");
-               goto end;
-       } else if (!S_ISDIR(stat_buf.st_mode)) {
-               char full_path[LTTNG_PATH_MAX];
-
-               /* Best effort for logging purposes. */
-               ret = get_full_path(ref_handle, path, full_path,
-                               sizeof(full_path));
-               if (ret) {
-                       full_path[0] = '\0';
-               }
-
-               ERR("Failed to initialize directory handle to \"%s\": not a directory",
-                               full_path);
-               goto end;
-       }
-       if (!path) {
-               new_handle = lttng_directory_handle_copy(ref_handle);
-               goto end;
-       }
-
-       path_len = strlen(path);
-       if (path_len == 0) {
-               ERR("Failed to initialize directory handle: provided path is an empty string");
-               ret = -1;
-               goto end;
-       }
-       if (*path == '/') {
-               new_path = strdup(path);
-               if (!new_path) {
-                       goto end;
-               }
-               /* Takes ownership of new_path. */
-               new_handle = _lttng_directory_handle_create(new_path);
-               new_path = NULL;
-               goto end;
-       }
-
-       add_trailing_slash = path[path_len - 1] != '/';
-
-       handle_path_len = strlen(ref_handle->base_path) + path_len +
-                       !!add_trailing_slash;
-       if (handle_path_len >= LTTNG_PATH_MAX) {
-               ERR("Failed to initialize directory handle as the resulting path's length (%zu bytes) exceeds the maximal allowed length (%d bytes)",
-                               handle_path_len, LTTNG_PATH_MAX);
-               goto end;
-       }
-       new_path = zmalloc(handle_path_len);
-       if (!new_path) {
-               PERROR("Failed to initialize directory handle");
-               goto end;
-       }
-
-       ret = sprintf(new_handle->base_path, "%s%s%s",
-                       ref_handle->base_path,
-                       path,
-                       add_trailing_slash ? "/" : "");
-       if (ret == -1 || ret >= handle_path_len) {
-               ERR("Failed to initialize directory handle: path formatting failed");
-               goto end;
-       }
-       new_handle = _lttng_directory_handle_create(new_path);
-       new_path = NULL;
-end:
-       free(new_path);
-       return new_handle;
-}
-
-struct lttng_directory_handle *lttng_directory_handle_create_from_dirfd(
-               int dirfd)
-{
-       LTTNG_ASSERT(dirfd == AT_FDCWD);
-       return lttng_directory_handle_create(NULL);
-}
-
-static
-void lttng_directory_handle_release(struct urcu_ref *ref)
-{
-       struct lttng_directory_handle *handle =
-                       container_of(ref, struct lttng_directory_handle, ref);
-
-       free(handle->base_path);
-       lttng_directory_handle_invalidate(handle);
-       free(handle);
-}
-
-struct lttng_directory_handle *lttng_directory_handle_copy(
-               const struct lttng_directory_handle *handle)
-{
-       struct lttng_directory_handle *new_handle = NULL;
-       char *new_path = NULL;
-
-       if (handle->base_path) {
-               new_path = strdup(handle->base_path);
-               if (!new_path) {
-                       goto end;
-               }
-       }
-       new_handle = _lttng_directory_handle_create(new_path);
-end:
-       return new_handle;
-}
-
-bool lttng_directory_handle_equals(const struct lttng_directory_handle *lhs,
-               const struct lttng_directory_handle *rhs)
-{
-       return strcmp(lhs->base_path, rhs->base_path) == 0;
-}
-
-static
-void lttng_directory_handle_invalidate(struct lttng_directory_handle *handle)
-{
-       handle->base_path = NULL;
-}
-
-int lttng_directory_handle_stat(const struct lttng_directory_handle *handle,
-               const char *subdirectory, struct stat *st)
-{
-       int ret;
-       char fullpath[LTTNG_PATH_MAX];
-
-       ret = get_full_path(handle, subdirectory, fullpath, sizeof(fullpath));
-       if (ret) {
-               errno = ENOMEM;
-               goto end;
-       }
-
-       ret = stat(fullpath, st);
-end:
-       return ret;
-}
-
-bool lttng_directory_handle_uses_fd(
-               const struct lttng_directory_handle *handle)
-{
-       return false;
-}
-
-static
-int lttng_directory_handle_mkdir(const struct lttng_directory_handle *handle,
-               const char *subdirectory, mode_t mode)
-{
-       int ret;
-       char fullpath[LTTNG_PATH_MAX];
-
-       ret = get_full_path(handle, subdirectory, fullpath, sizeof(fullpath));
-       if (ret) {
-               errno = ENOMEM;
-               goto end;
-       }
-
-       ret = mkdir(fullpath, mode);
-end:
-       return ret;
-}
-
-static
-int lttng_directory_handle_open(const struct lttng_directory_handle *handle,
-               const char *filename, int flags, mode_t mode)
-{
-       int ret;
-       char fullpath[LTTNG_PATH_MAX];
-
-       ret = get_full_path(handle, filename, fullpath, sizeof(fullpath));
-       if (ret) {
-               errno = ENOMEM;
-               goto end;
-       }
-
-       ret = open(fullpath, flags, mode);
-end:
-       return ret;
-}
-
-static
-int lttng_directory_handle_unlink(
-               const struct lttng_directory_handle *handle,
-               const char *filename)
-{
-       int ret;
-       char fullpath[LTTNG_PATH_MAX];
-
-       ret = get_full_path(handle, filename, fullpath, sizeof(fullpath));
-       if (ret) {
-               errno = ENOMEM;
-               goto end;
-       }
-
-       ret = unlink(fullpath);
-end:
-       return ret;
-}
-
-static
-int _run_as_mkdir(const struct lttng_directory_handle *handle, const char *path,
-               mode_t mode, uid_t uid, gid_t gid)
-{
-       int ret;
-       char fullpath[LTTNG_PATH_MAX];
-
-       ret = get_full_path(handle, path, fullpath, sizeof(fullpath));
-       if (ret) {
-               errno = ENOMEM;
-               goto end;
-       }
-
-       ret = run_as_mkdir(fullpath, mode, uid, gid);
-end:
-       return ret;
-}
-
-static
-int _run_as_open(const struct lttng_directory_handle *handle,
-               const char *filename,
-               int flags, mode_t mode, uid_t uid, gid_t gid)
-{
-       int ret;
-       char fullpath[LTTNG_PATH_MAX];
-
-       ret = get_full_path(handle, filename, fullpath, sizeof(fullpath));
-       if (ret) {
-               errno = ENOMEM;
-               goto end;
-       }
-
-       ret = run_as_open(fullpath, flags, mode, uid, gid);
-end:
-       return ret;
-}
-
-static
-int _run_as_unlink(const struct lttng_directory_handle *handle,
-               const char *filename, uid_t uid, gid_t gid)
-{
-       int ret;
-       char fullpath[LTTNG_PATH_MAX];
-
-       ret = get_full_path(handle, filename, fullpath, sizeof(fullpath));
-       if (ret) {
-               errno = ENOMEM;
-               goto end;
-       }
-
-       ret = run_as_unlink(fullpath, uid, gid);
-end:
-       return ret;
-}
-
-static
-int _run_as_mkdir_recursive(const struct lttng_directory_handle *handle,
-               const char *path, mode_t mode, uid_t uid, gid_t gid)
-{
-       int ret;
-       char fullpath[LTTNG_PATH_MAX];
-
-       ret = get_full_path(handle, path, fullpath, sizeof(fullpath));
-       if (ret) {
-               errno = ENOMEM;
-               goto end;
-       }
-
-       ret = run_as_mkdir_recursive(fullpath, mode, uid, gid);
-end:
-       return ret;
-}
-
-static
-int _lttng_directory_handle_rename(
-               const struct lttng_directory_handle *old_handle,
-               const char *old_name,
-               const struct lttng_directory_handle *new_handle,
-               const char *new_name)
-{
-       int ret;
-       char old_fullpath[LTTNG_PATH_MAX];
-       char new_fullpath[LTTNG_PATH_MAX];
-
-       ret = get_full_path(old_handle, old_name, old_fullpath,
-                       sizeof(old_fullpath));
-       if (ret) {
-               errno = ENOMEM;
-               goto end;
-       }
-       ret = get_full_path(new_handle, new_name, new_fullpath,
-                       sizeof(new_fullpath));
-       if (ret) {
-               errno = ENOMEM;
-               goto end;
-       }
-
-       ret = rename(old_fullpath, new_fullpath);
-end:
-       return ret;
-}
-
-static
-int _run_as_rename(const struct lttng_directory_handle *old_handle,
-               const char *old_name,
-               const struct lttng_directory_handle *new_handle,
-               const char *new_name, uid_t uid, gid_t gid)
-{
-       int ret;
-       char old_fullpath[LTTNG_PATH_MAX];
-       char new_fullpath[LTTNG_PATH_MAX];
-
-       ret = get_full_path(old_handle, old_name, old_fullpath,
-                       sizeof(old_fullpath));
-       if (ret) {
-               errno = ENOMEM;
-               goto end;
-       }
-       ret = get_full_path(new_handle, new_name, new_fullpath,
-                       sizeof(new_fullpath));
-       if (ret) {
-               errno = ENOMEM;
-               goto end;
-       }
-
-       ret = run_as_rename(old_fullpath, new_fullpath, uid, gid);
-end:
-       return ret;
-}
-
-static
-DIR *lttng_directory_handle_opendir(const struct lttng_directory_handle *handle,
-               const char *path)
-{
-       int ret;
-       DIR *dir_stream = NULL;
-       char fullpath[LTTNG_PATH_MAX];
-
-       ret = get_full_path(handle, path, fullpath, sizeof(fullpath));
-       if (ret) {
-               errno = ENOMEM;
-               goto end;
-       }
-
-       dir_stream = opendir(fullpath);
-end:
-       return dir_stream;
-}
-
-static
-int lttng_directory_handle_rmdir(
-               const struct lttng_directory_handle *handle, const char *name)
-{
-       int ret;
-       char fullpath[LTTNG_PATH_MAX];
-
-       ret = get_full_path(handle, name, fullpath, sizeof(fullpath));
-       if (ret) {
-               errno = ENOMEM;
-               goto end;
-       }
-
-       ret = rmdir(fullpath);
-end:
-       return ret;
-}
-
-static
-int _run_as_rmdir(const struct lttng_directory_handle *handle,
-               const char *name, uid_t uid, gid_t gid)
-{
-       int ret;
-       char fullpath[LTTNG_PATH_MAX];
-
-       ret = get_full_path(handle, name, fullpath, sizeof(fullpath));
-       if (ret) {
-               errno = ENOMEM;
-               goto end;
-       }
-
-       ret = run_as_rmdir(fullpath, uid, gid);
-end:
-       return ret;
-}
-
-static
-int _run_as_rmdir_recursive(
-               const struct lttng_directory_handle *handle, const char *name,
-               uid_t uid, gid_t gid, int flags)
-{
-       int ret;
-       char fullpath[LTTNG_PATH_MAX];
-
-       ret = get_full_path(handle, name, fullpath, sizeof(fullpath));
-       if (ret) {
-               errno = ENOMEM;
-               goto end;
-       }
-
-       ret = run_as_rmdir_recursive(fullpath, uid, gid, flags);
-end:
-       return ret;
-}
-
-#endif /* HAVE_DIRFD */
-
-/* Common implementation. */
-
-/*
- * On some filesystems (e.g. nfs), mkdir will validate access rights before
- * checking for the existence of the path element. This means that on a setup
- * where "/home/" is a mounted NFS share, and running as an unpriviledged user,
- * recursively creating a path of the form "/home/my_user/trace/" will fail with
- * EACCES on mkdir("/home", ...).
- *
- * Checking the path for existence allows us to work around this behaviour.
- */
-static
-int create_directory_check_exists(const struct lttng_directory_handle *handle,
-               const char *path, mode_t mode)
-{
-       int ret = 0;
-       struct stat st;
-
-       ret = lttng_directory_handle_stat(handle, path, &st);
-       if (ret == 0) {
-               if (S_ISDIR(st.st_mode)) {
-                       /* Directory exists, skip. */
-                       goto end;
-               } else {
-                       /* Exists, but is not a directory. */
-                       errno = ENOTDIR;
-                       ret = -1;
-                       goto end;
-               }
-       } else if (errno != ENOENT) {
-               goto end;
-       }
-
-       /*
-        * Let mkdir handle other errors as the caller expects mkdir
-        * semantics.
-        */
-       ret = lttng_directory_handle_mkdir(handle, path, mode);
-end:
-       return ret;
-}
-
-static
-int create_directory_recursive(const struct lttng_directory_handle *handle,
-               const char *path, mode_t mode)
-{
-       char *p, tmp[LTTNG_PATH_MAX];
-       size_t len;
-       int ret;
-
-       LTTNG_ASSERT(path);
-
-       ret = lttng_strncpy(tmp, path, sizeof(tmp));
-       if (ret) {
-               ERR("Failed to create directory: provided path's length (%zu bytes) exceeds the maximal allowed length (%zu bytes)",
-                               strlen(path) + 1, sizeof(tmp));
-               goto error;
-       }
-
-       len = strlen(path);
-       if (tmp[len - 1] == '/') {
-               tmp[len - 1] = 0;
-       }
-
-       for (p = tmp + 1; *p; p++) {
-               if (*p == '/') {
-                       *p = 0;
-                       if (tmp[strlen(tmp) - 1] == '.' &&
-                                       tmp[strlen(tmp) - 2] == '.' &&
-                                       tmp[strlen(tmp) - 3] == '/') {
-                               ERR("Using '/../' is not permitted in the trace path (%s)",
-                                               tmp);
-                               ret = -1;
-                               goto error;
-                       }
-                       ret = create_directory_check_exists(handle, tmp, mode);
-                       if (ret < 0) {
-                               if (errno != EACCES) {
-                                       PERROR("Failed to create directory \"%s\"",
-                                                       path);
-                                       ret = -errno;
-                                       goto error;
-                               }
-                       }
-                       *p = '/';
-               }
-       }
-
-       ret = create_directory_check_exists(handle, tmp, mode);
-       if (ret < 0) {
-               PERROR("mkdirat recursive last element");
-               ret = -errno;
-       }
-error:
-       return ret;
-}
-
-bool lttng_directory_handle_get(struct lttng_directory_handle *handle)
-{
-       return urcu_ref_get_unless_zero(&handle->ref);
-}
-
-void lttng_directory_handle_put(struct lttng_directory_handle *handle)
-{
-       if (!handle) {
-               return;
-       }
-       LTTNG_ASSERT(handle->ref.refcount);
-       urcu_ref_put(&handle->ref, lttng_directory_handle_release);
-}
-
-int lttng_directory_handle_create_subdirectory_as_user(
-               const struct lttng_directory_handle *handle,
-               const char *subdirectory,
-               mode_t mode, const struct lttng_credentials *creds)
-{
-       int ret;
-
-       if (!creds) {
-               /* Run as current user. */
-               ret = create_directory_check_exists(handle,
-                               subdirectory, mode);
-       } else {
-               ret = _run_as_mkdir(handle, subdirectory, mode,
-                               lttng_credentials_get_uid(creds),
-                               lttng_credentials_get_gid(creds));
-       }
-
-       return ret;
-}
-
-int lttng_directory_handle_create_subdirectory_recursive_as_user(
-               const struct lttng_directory_handle *handle,
-               const char *subdirectory_path,
-               mode_t mode, const struct lttng_credentials *creds)
-{
-       int ret;
-
-       if (!creds) {
-               /* Run as current user. */
-               ret = create_directory_recursive(handle,
-                               subdirectory_path, mode);
-       } else {
-               ret = _run_as_mkdir_recursive(handle, subdirectory_path,
-                               mode, lttng_credentials_get_uid(creds), lttng_credentials_get_gid(creds));
-       }
-
-       return ret;
-}
-
-int lttng_directory_handle_create_subdirectory(
-               const struct lttng_directory_handle *handle,
-               const char *subdirectory,
-               mode_t mode)
-{
-       return lttng_directory_handle_create_subdirectory_as_user(
-                       handle, subdirectory, mode, NULL);
-}
-
-int lttng_directory_handle_create_subdirectory_recursive(
-               const struct lttng_directory_handle *handle,
-               const char *subdirectory_path,
-               mode_t mode)
-{
-       return lttng_directory_handle_create_subdirectory_recursive_as_user(
-                       handle, subdirectory_path, mode, NULL);
-}
-
-int lttng_directory_handle_open_file_as_user(
-               const struct lttng_directory_handle *handle,
-               const char *filename,
-               int flags, mode_t mode,
-               const struct lttng_credentials *creds)
-{
-       int ret;
-
-       if (!creds) {
-               /* Run as current user. */
-               ret = lttng_directory_handle_open(handle, filename, flags,
-                               mode);
-       } else {
-               ret = _run_as_open(handle, filename, flags, mode,
-                               lttng_credentials_get_uid(creds), lttng_credentials_get_gid(creds));
-       }
-       return ret;
-}
-
-int lttng_directory_handle_open_file(
-               const struct lttng_directory_handle *handle,
-               const char *filename,
-               int flags, mode_t mode)
-{
-       return lttng_directory_handle_open_file_as_user(handle, filename, flags,
-                       mode, NULL);
-}
-
-int lttng_directory_handle_unlink_file_as_user(
-               const struct lttng_directory_handle *handle,
-               const char *filename,
-               const struct lttng_credentials *creds)
-{
-       int ret;
-
-       if (!creds) {
-               /* Run as current user. */
-               ret = lttng_directory_handle_unlink(handle, filename);
-       } else {
-               ret = _run_as_unlink(handle, filename, lttng_credentials_get_uid(creds), lttng_credentials_get_gid(creds));
-       }
-       return ret;
-}
-
-int lttng_directory_handle_unlink_file(
-               const struct lttng_directory_handle *handle,
-               const char *filename)
-{
-       return lttng_directory_handle_unlink_file_as_user(handle,
-                       filename, NULL);
-}
-
-int lttng_directory_handle_rename(
-               const struct lttng_directory_handle *old_handle,
-               const char *old_name,
-               const struct lttng_directory_handle *new_handle,
-               const char *new_name)
-{
-       return lttng_directory_handle_rename_as_user(old_handle, old_name,
-                       new_handle, new_name, NULL);
-}
-
-int lttng_directory_handle_rename_as_user(
-               const struct lttng_directory_handle *old_handle,
-               const char *old_name,
-               const struct lttng_directory_handle *new_handle,
-               const char *new_name,
-               const struct lttng_credentials *creds)
-{
-       int ret;
-
-       if (!creds) {
-               /* Run as current user. */
-               ret = _lttng_directory_handle_rename(old_handle,
-                               old_name, new_handle, new_name);
-       } else {
-               ret = _run_as_rename(old_handle, old_name, new_handle,
-                               new_name, lttng_credentials_get_uid(creds), lttng_credentials_get_gid(creds));
-       }
-       return ret;
-}
-
-int lttng_directory_handle_remove_subdirectory(
-               const struct lttng_directory_handle *handle,
-               const char *name)
-{
-       return lttng_directory_handle_remove_subdirectory_as_user(handle, name,
-                       NULL);
-}
-
-int lttng_directory_handle_remove_subdirectory_as_user(
-               const struct lttng_directory_handle *handle,
-               const char *name,
-               const struct lttng_credentials *creds)
-{
-       int ret;
-
-       if (!creds) {
-               /* Run as current user. */
-               ret = lttng_directory_handle_rmdir(handle, name);
-       } else {
-               ret = _run_as_rmdir(handle, name, lttng_credentials_get_uid(creds), lttng_credentials_get_gid(creds));
-       }
-       return ret;
-}
-
-struct rmdir_frame {
-       ssize_t parent_frame_idx;
-       DIR *dir;
-       bool empty;
-       /* Size including '\0'. */
-       size_t path_size;
-};
-
-static
-void rmdir_frame_fini(void *data)
-{
-       int ret;
-       struct rmdir_frame *frame = data;
-
-       ret = closedir(frame->dir);
-       if (ret == -1) {
-               PERROR("Failed to close directory stream");
-       }
-}
-
-static
-int remove_directory_recursive(const struct lttng_directory_handle *handle,
-               const char *path, int flags)
-{
-       int ret;
-       struct lttng_dynamic_array frames;
-       size_t current_frame_idx = 0;
-       struct rmdir_frame initial_frame = {
-               .parent_frame_idx = -1,
-               .dir = lttng_directory_handle_opendir(handle, path),
-               .empty = true,
-               .path_size = strlen(path) + 1,
-       };
-       struct lttng_dynamic_buffer current_path;
-       const char separator = '/';
-
-       lttng_dynamic_buffer_init(&current_path);
-       lttng_dynamic_array_init(&frames, sizeof(struct rmdir_frame),
-                       rmdir_frame_fini);
-
-       if (flags & ~(LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG |
-                                   LTTNG_DIRECTORY_HANDLE_FAIL_NON_EMPTY_FLAG)) {
-               ERR("Unknown flags %d", flags);
-               ret = -1;
-               goto end;
-       }
-
-       if (!initial_frame.dir) {
-               if (flags & LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG &&
-                               errno == ENOENT) {
-                       DBG("Cannot rmdir \"%s\": root does not exist", path);
-                       ret = 0;
-                       goto end;
-               } else {
-                       PERROR("Failed to rmdir \"%s\"", path);
-                       ret = -1;
-                       goto end;
-               }
-       }
-
-       ret = lttng_dynamic_array_add_element(&frames, &initial_frame);
-       if (ret) {
-               ERR("Failed to push context frame during recursive directory removal");
-               rmdir_frame_fini(&initial_frame);
-               goto end;
-       }
-
-       ret = lttng_dynamic_buffer_append(
-                       &current_path, path, initial_frame.path_size);
-       if (ret) {
-               ERR("Failed to set initial path during recursive directory removal");
-               ret = -1;
-               goto end;
-       }
-
-       while (lttng_dynamic_array_get_count(&frames) > 0) {
-               struct dirent *entry;
-               struct rmdir_frame *current_frame =
-                               lttng_dynamic_array_get_element(
-                                               &frames, current_frame_idx);
-
-               LTTNG_ASSERT(current_frame->dir);
-               ret = lttng_dynamic_buffer_set_size(
-                               &current_path, current_frame->path_size);
-               LTTNG_ASSERT(!ret);
-               current_path.data[current_path.size - 1] = '\0';
-
-               while ((entry = readdir(current_frame->dir))) {
-                       struct stat st;
-
-                       if (!strcmp(entry->d_name, ".") ||
-                                       !strcmp(entry->d_name, "..")) {
-                               continue;
-                       }
-
-                       /* Set current_path to the entry's path. */
-                       ret = lttng_dynamic_buffer_set_size(
-                                       &current_path, current_path.size - 1);
-                       LTTNG_ASSERT(!ret);
-                       ret = lttng_dynamic_buffer_append(&current_path,
-                                       &separator, sizeof(separator));
-                       if (ret) {
-                               goto end;
-                       }
-                       ret = lttng_dynamic_buffer_append(&current_path,
-                                       entry->d_name,
-                                       strlen(entry->d_name) + 1);
-                       if (ret) {
-                               goto end;
-                       }
-
-                       if (lttng_directory_handle_stat(
-                                           handle, current_path.data, &st)) {
-                               if ((flags & LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG) &&
-                                               errno == ENOENT) {
-                                       break;
-                               }
-                               PERROR("Failed to stat \"%s\"",
-                                               current_path.data);
-                               ret = -1;
-                               goto end;
-                       }
-
-                       if (!S_ISDIR(st.st_mode)) {
-                               if (flags & LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG) {
-                                       current_frame->empty = false;
-                                       break;
-                               } else {
-                                       /* Not empty, abort. */
-                                       DBG("Directory \"%s\" is not empty; refusing to remove directory",
-                                                       current_path.data);
-                                       ret = -1;
-                                       goto end;
-                               }
-                       } else {
-                               struct rmdir_frame new_frame = {
-                                       .path_size = current_path.size,
-                                       .dir = lttng_directory_handle_opendir(
-                                                       handle,
-                                                       current_path.data),
-                                       .empty = true,
-                                       .parent_frame_idx = current_frame_idx,
-                               };
-
-                               if (!new_frame.dir) {
-                                       if (flags & LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG &&
-                                                       errno == ENOENT) {
-                                               DBG("Non-existing directory stream during recursive directory removal");
-                                               break;
-                                       } else {
-                                               PERROR("Failed to open directory stream during recursive directory removal");
-                                               ret = -1;
-                                               goto end;
-                                       }
-                               }
-                               ret = lttng_dynamic_array_add_element(
-                                               &frames, &new_frame);
-                               if (ret) {
-                                       ERR("Failed to push context frame during recursive directory removal");
-                                       rmdir_frame_fini(&new_frame);
-                                       goto end;
-                               }
-                               current_frame_idx++;
-                               /* We break iteration on readdir. */
-                               break;
-                       }
-               }
-               if (entry) {
-                       continue;
-               }
-
-               /* Pop rmdir frame. */
-               if (current_frame->empty) {
-                       ret = lttng_directory_handle_rmdir(
-                                       handle, current_path.data);
-                       if (ret) {
-                               if ((flags & LTTNG_DIRECTORY_HANDLE_FAIL_NON_EMPTY_FLAG) ||
-                                               errno != ENOENT) {
-                                       PERROR("Failed to remove \"%s\" during recursive directory removal",
-                                                       current_path.data);
-                                       goto end;
-                               }
-                               DBG("Non-existing directory stream during recursive directory removal");
-                       }
-               } else if (current_frame->parent_frame_idx >= 0) {
-                       struct rmdir_frame *parent_frame;
-
-                       parent_frame = lttng_dynamic_array_get_element(&frames,
-                                       current_frame->parent_frame_idx);
-                       LTTNG_ASSERT(parent_frame);
-                       parent_frame->empty = false;
-               }
-               ret = lttng_dynamic_array_remove_element(
-                               &frames, current_frame_idx);
-               if (ret) {
-                       ERR("Failed to pop context frame during recursive directory removal");
-                       goto end;
-               }
-               current_frame_idx--;
-       }
-end:
-       lttng_dynamic_array_reset(&frames);
-       lttng_dynamic_buffer_reset(&current_path);
-       return ret;
-}
-
-int lttng_directory_handle_remove_subdirectory_recursive(
-               const struct lttng_directory_handle *handle,
-               const char *name,
-               int flags)
-{
-       return lttng_directory_handle_remove_subdirectory_recursive_as_user(
-                       handle, name, NULL, flags);
-}
-
-int lttng_directory_handle_remove_subdirectory_recursive_as_user(
-               const struct lttng_directory_handle *handle,
-               const char *name,
-               const struct lttng_credentials *creds,
-               int flags)
-{
-       int ret;
-
-       if (!creds) {
-               /* Run as current user. */
-               ret = remove_directory_recursive(handle, name, flags);
-       } else {
-               ret = _run_as_rmdir_recursive(handle, name, lttng_credentials_get_uid(creds),
-                               lttng_credentials_get_gid(creds), flags);
-       }
-       return ret;
-}
diff --git a/src/common/compat/directory-handle.cpp b/src/common/compat/directory-handle.cpp
new file mode 100644 (file)
index 0000000..edd82eb
--- /dev/null
@@ -0,0 +1,1385 @@
+/*
+ * Copyright (C) 2019 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#include <common/compat/directory-handle.h>
+#include <common/error.h>
+#include <common/macros.h>
+#include <common/runas.h>
+#include <common/credentials.h>
+#include <lttng/constant.h>
+#include <common/dynamic-array.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <dirent.h>
+
+/*
+ * This compatibility layer shares a common "base" that is implemented
+ * in terms of an internal API. This file contains two implementations
+ * of the internal API below.
+ */
+static
+int lttng_directory_handle_mkdir(
+               const struct lttng_directory_handle *handle,
+               const char *path, mode_t mode);
+static
+int _run_as_mkdir(const struct lttng_directory_handle *handle, const char *path,
+               mode_t mode, uid_t uid, gid_t gid);
+static
+int _run_as_mkdir_recursive(const struct lttng_directory_handle *handle,
+               const char *path, mode_t mode, uid_t uid, gid_t gid);
+static
+int lttng_directory_handle_open(const struct lttng_directory_handle *handle,
+               const char *filename, int flags, mode_t mode);
+static
+int _run_as_open(const struct lttng_directory_handle *handle,
+               const char *filename,
+               int flags, mode_t mode, uid_t uid, gid_t gid);
+static
+int lttng_directory_handle_unlink(
+               const struct lttng_directory_handle *handle,
+               const char *filename);
+static
+int _run_as_unlink(const struct lttng_directory_handle *handle,
+               const char *filename, uid_t uid, gid_t gid);
+static
+int _lttng_directory_handle_rename(
+               const struct lttng_directory_handle *old_handle,
+               const char *old_name,
+               const struct lttng_directory_handle *new_handle,
+               const char *new_name);
+static
+int _run_as_rename(const struct lttng_directory_handle *old_handle,
+               const char *old_name,
+               const struct lttng_directory_handle *new_handle,
+               const char *new_name, uid_t uid, gid_t gid);
+static
+DIR *lttng_directory_handle_opendir(const struct lttng_directory_handle *handle,
+               const char *path);
+static
+int lttng_directory_handle_rmdir(
+               const struct lttng_directory_handle *handle, const char *name);
+static
+int _run_as_rmdir(const struct lttng_directory_handle *handle,
+               const char *name, uid_t uid, gid_t gid);
+static
+int _run_as_rmdir_recursive(
+               const struct lttng_directory_handle *handle, const char *name,
+               uid_t uid, gid_t gid, int flags);
+static
+void lttng_directory_handle_invalidate(struct lttng_directory_handle *handle);
+static
+void lttng_directory_handle_release(struct urcu_ref *ref);
+
+#ifdef HAVE_DIRFD
+
+/*
+ * Special inode number reserved to represent the "current working directory".
+ * ino_t is spec'ed as being an unsigned integral type.
+ */
+#define RESERVED_AT_FDCWD_INO                      \
+       ({                                         \
+               uint64_t reserved_val;             \
+               switch (sizeof(ino_t)) {           \
+               case 4:                            \
+                       reserved_val = UINT32_MAX; \
+                       break;                     \
+               case 8:                            \
+                       reserved_val = UINT64_MAX; \
+                       break;                     \
+               default:                           \
+                       abort();                   \
+               }                                  \
+               (ino_t) reserved_val;              \
+       })
+
+struct lttng_directory_handle *lttng_directory_handle_create(const char *path)
+{
+       lttng_directory_handle cwd_handle {};
+       cwd_handle.dirfd = AT_FDCWD;
+
+       /* Open a handle to the CWD if NULL is passed. */
+       return lttng_directory_handle_create_from_handle(path, &cwd_handle);
+}
+
+struct lttng_directory_handle *lttng_directory_handle_create_from_handle(
+               const char *path,
+               const struct lttng_directory_handle *ref_handle)
+{
+       int dirfd;
+       struct lttng_directory_handle *handle = NULL;
+
+       if (!path) {
+               handle = lttng_directory_handle_copy(ref_handle);
+               goto end;
+       }
+       if (!*path) {
+               ERR("Failed to initialize directory handle: provided path is an empty string");
+               goto end;
+       }
+
+       dirfd = openat(ref_handle->dirfd, path, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
+       if (dirfd == -1) {
+               PERROR("Failed to initialize directory handle to \"%s\"", path);
+               goto end;
+       }
+
+       handle = lttng_directory_handle_create_from_dirfd(dirfd);
+       if (!handle) {
+               goto error_close;
+       }
+end:
+       return handle;
+error_close:
+       if (close(dirfd)) {
+               PERROR("Failed to close directory file descriptor");
+       }
+       return NULL;
+}
+
+struct lttng_directory_handle *lttng_directory_handle_create_from_dirfd(
+               int dirfd)
+{
+       int ret;
+       struct lttng_directory_handle *handle = (lttng_directory_handle *) zmalloc(sizeof(*handle));
+       struct stat stat_buf;
+
+       if (!handle) {
+               goto end;
+       }
+
+       if (dirfd != AT_FDCWD) {
+               ret = fstat(dirfd, &stat_buf);
+               if (ret) {
+                       PERROR("Failed to fstat directory file descriptor %i", dirfd);
+                       lttng_directory_handle_release(&handle->ref);
+                       handle = NULL;
+                       goto end;
+               }
+       } else {
+               handle->directory_inode = RESERVED_AT_FDCWD_INO;
+       }
+       handle->dirfd = dirfd;
+       urcu_ref_init(&handle->ref);
+end:
+       return handle;
+}
+
+static
+void lttng_directory_handle_release(struct urcu_ref *ref)
+{
+       int ret;
+       struct lttng_directory_handle *handle =
+                       container_of(ref, struct lttng_directory_handle, ref);
+
+       if (handle->destroy_cb) {
+               handle->destroy_cb(handle, handle->destroy_cb_data);
+       }
+
+       if (handle->dirfd == AT_FDCWD || handle->dirfd == -1) {
+               goto end;
+       }
+       ret = close(handle->dirfd);
+       if (ret == -1) {
+               PERROR("Failed to close directory file descriptor of directory handle");
+       }
+end:
+       lttng_directory_handle_invalidate(handle);
+       free(handle);
+}
+
+struct lttng_directory_handle *lttng_directory_handle_copy(
+               const struct lttng_directory_handle *handle)
+{
+       struct lttng_directory_handle *new_handle = NULL;
+
+       if (handle->dirfd == AT_FDCWD) {
+               new_handle = lttng_directory_handle_create_from_dirfd(AT_FDCWD);
+       } else {
+               const int new_dirfd = dup(handle->dirfd);
+
+               if (new_dirfd == -1) {
+                       PERROR("Failed to duplicate directory file descriptor of directory handle");
+                       goto end;
+               }
+               new_handle = lttng_directory_handle_create_from_dirfd(
+                               new_dirfd);
+               if (!new_handle && close(new_dirfd)) {
+                       PERROR("Failed to close directory file descriptor of directory handle");
+               }
+       }
+end:
+       return new_handle;
+}
+
+bool lttng_directory_handle_equals(const struct lttng_directory_handle *lhs,
+               const struct lttng_directory_handle *rhs)
+{
+       return lhs->directory_inode == rhs->directory_inode;
+}
+
+static
+void lttng_directory_handle_invalidate(struct lttng_directory_handle *handle)
+{
+       handle->dirfd = -1;
+}
+
+int lttng_directory_handle_stat(const struct lttng_directory_handle *handle,
+               const char *path, struct stat *st)
+{
+       return fstatat(handle->dirfd, path, st, 0);
+}
+
+bool lttng_directory_handle_uses_fd(
+               const struct lttng_directory_handle *handle)
+{
+       return handle->dirfd != AT_FDCWD;
+}
+
+static
+int lttng_directory_handle_mkdir(
+               const struct lttng_directory_handle *handle,
+               const char *path, mode_t mode)
+{
+       return mkdirat(handle->dirfd, path, mode);
+}
+
+static
+int lttng_directory_handle_open(const struct lttng_directory_handle *handle,
+               const char *filename, int flags, mode_t mode)
+{
+       return openat(handle->dirfd, filename, flags, mode);
+}
+
+static
+int _run_as_open(const struct lttng_directory_handle *handle,
+               const char *filename,
+               int flags, mode_t mode, uid_t uid, gid_t gid)
+{
+       return run_as_openat(handle->dirfd, filename, flags, mode, uid, gid);
+}
+
+static
+int _run_as_unlink(const struct lttng_directory_handle *handle,
+               const char *filename, uid_t uid, gid_t gid)
+{
+       return run_as_unlinkat(handle->dirfd, filename, uid, gid);
+}
+
+static
+int lttng_directory_handle_unlink(
+               const struct lttng_directory_handle *handle,
+               const char *filename)
+{
+       return unlinkat(handle->dirfd, filename, 0);
+}
+
+static
+int _run_as_mkdir(const struct lttng_directory_handle *handle,
+               const char *path, mode_t mode, uid_t uid, gid_t gid)
+{
+       return run_as_mkdirat(handle->dirfd, path, mode, uid, gid);
+}
+
+static
+int _run_as_mkdir_recursive(const struct lttng_directory_handle *handle,
+               const char *path, mode_t mode, uid_t uid, gid_t gid)
+{
+       return run_as_mkdirat_recursive(handle->dirfd, path, mode, uid, gid);
+}
+
+static
+int _lttng_directory_handle_rename(
+               const struct lttng_directory_handle *old_handle,
+               const char *old_name,
+               const struct lttng_directory_handle *new_handle,
+               const char *new_name)
+{
+       return renameat(old_handle->dirfd, old_name,
+                       new_handle->dirfd, new_name);
+}
+
+static
+int _run_as_rename(const struct lttng_directory_handle *old_handle,
+               const char *old_name,
+               const struct lttng_directory_handle *new_handle,
+               const char *new_name, uid_t uid, gid_t gid)
+{
+       return run_as_renameat(old_handle->dirfd, old_name, new_handle->dirfd,
+                       new_name, uid, gid);
+}
+
+static
+DIR *lttng_directory_handle_opendir(const struct lttng_directory_handle *handle,
+               const char *path)
+{
+       DIR *dir_stream = NULL;
+       int fd = openat(handle->dirfd, path, O_RDONLY);
+
+       if (fd < 0) {
+               goto end;
+       }
+
+       dir_stream = fdopendir(fd);
+       if (!dir_stream) {
+               int ret;
+
+               PERROR("Failed to open directory stream");
+               ret = close(fd);
+               if (ret) {
+                       PERROR("Failed to close file descriptor to %s", path);
+               }
+               goto end;
+       }
+
+end:
+       return dir_stream;
+}
+
+static
+int lttng_directory_handle_rmdir(
+               const struct lttng_directory_handle *handle, const char *name)
+{
+       int ret = unlinkat(handle->dirfd, name, AT_REMOVEDIR);
+       if (ret) {
+               PERROR("Failed to remove directory `%s`", name);
+       }
+
+       return ret;
+}
+
+static
+int _run_as_rmdir(const struct lttng_directory_handle *handle,
+               const char *name, uid_t uid, gid_t gid)
+{
+       return run_as_rmdirat(handle->dirfd, name, uid, gid);
+}
+
+static
+int _run_as_rmdir_recursive(
+               const struct lttng_directory_handle *handle, const char *name,
+               uid_t uid, gid_t gid, int flags)
+{
+       return run_as_rmdirat_recursive(handle->dirfd, name, uid, gid, flags);
+}
+
+#else /* HAVE_DIRFD */
+
+static
+int get_full_path(const struct lttng_directory_handle *handle,
+               const char *subdirectory, char *fullpath, size_t size)
+{
+       int ret;
+       const bool subdirectory_is_absolute =
+                       subdirectory && *subdirectory == '/';
+       const char * const base = subdirectory_is_absolute ?
+                       subdirectory : handle->base_path;
+       const char * const end = subdirectory && !subdirectory_is_absolute ?
+                       subdirectory : NULL;
+       const size_t base_len = strlen(base);
+       const size_t end_len = end ? strlen(end) : 0;
+       const bool add_separator_slash = end && base[base_len - 1] != '/';
+       const bool add_trailing_slash = end && end[end_len - 1] != '/';
+
+       ret = snprintf(fullpath, size, "%s%s%s%s",
+                       base,
+                       add_separator_slash ? "/" : "",
+                       end ? end : "",
+                       add_trailing_slash ? "/" : "");
+       if (ret == -1 || ret >= size) {
+               ERR("Failed to format subdirectory from directory handle");
+               ret = -1;
+               goto end;
+       }
+       ret = 0;
+end:
+       return ret;
+}
+
+static
+struct lttng_directory_handle *_lttng_directory_handle_create(char *path)
+{
+       struct lttng_directory_handle *handle = zmalloc(sizeof(*handle));
+
+       if (!handle) {
+               goto end;
+       }
+       urcu_ref_init(&handle->ref);
+       handle->base_path = path;
+end:
+       return handle;
+}
+
+struct lttng_directory_handle *lttng_directory_handle_create(
+               const char *path)
+{
+       int ret;
+       const char *cwd = "";
+       size_t cwd_len, path_len;
+       char cwd_buf[LTTNG_PATH_MAX] = {};
+       char handle_buf[LTTNG_PATH_MAX] = {};
+       struct lttng_directory_handle *new_handle = NULL;
+       bool add_cwd_slash = false, add_trailing_slash = false;
+       const struct lttng_directory_handle cwd_handle = {
+               .base_path = handle_buf,
+       };
+
+       path_len = path ? strlen(path) : 0;
+       add_trailing_slash = path && path[path_len - 1] != '/';
+       if (!path || (path && *path != '/')) {
+               cwd = getcwd(cwd_buf, sizeof(cwd_buf));
+               if (!cwd) {
+                       PERROR("Failed to initialize directory handle, can't get current working directory");
+                       ret = -1;
+                       goto end;
+               }
+               cwd_len = strlen(cwd);
+               if (cwd_len == 0) {
+                       ERR("Failed to initialize directory handle, current working directory path has a length of 0");
+                       ret = -1;
+                       goto end;
+               }
+               add_cwd_slash = cwd[cwd_len - 1] != '/';
+       }
+
+       ret = snprintf(handle_buf, sizeof(handle_buf), "%s%s%s%s",
+                       cwd,
+                       add_cwd_slash ? "/" : "",
+                       path ? : "",
+                       add_trailing_slash ? "/" : "");
+       if (ret == -1 || ret >= LTTNG_PATH_MAX) {
+               ERR("Failed to initialize directory handle, failed to format directory path");
+               goto end;
+       }
+
+       new_handle = lttng_directory_handle_create_from_handle(path, &cwd_handle);
+end:
+       return new_handle;
+}
+
+struct lttng_directory_handle *lttng_directory_handle_create_from_handle(
+               const char *path,
+               const struct lttng_directory_handle *ref_handle)
+{
+       int ret;
+       size_t path_len, handle_path_len;
+       bool add_trailing_slash;
+       struct stat stat_buf;
+       struct lttng_directory_handle *new_handle = NULL;
+       char *new_path = NULL;
+
+       LTTNG_ASSERT(ref_handle && ref_handle->base_path);
+
+       ret = lttng_directory_handle_stat(ref_handle, path, &stat_buf);
+       if (ret == -1) {
+               PERROR("Failed to create directory handle");
+               goto end;
+       } else if (!S_ISDIR(stat_buf.st_mode)) {
+               char full_path[LTTNG_PATH_MAX];
+
+               /* Best effort for logging purposes. */
+               ret = get_full_path(ref_handle, path, full_path,
+                               sizeof(full_path));
+               if (ret) {
+                       full_path[0] = '\0';
+               }
+
+               ERR("Failed to initialize directory handle to \"%s\": not a directory",
+                               full_path);
+               goto end;
+       }
+       if (!path) {
+               new_handle = lttng_directory_handle_copy(ref_handle);
+               goto end;
+       }
+
+       path_len = strlen(path);
+       if (path_len == 0) {
+               ERR("Failed to initialize directory handle: provided path is an empty string");
+               ret = -1;
+               goto end;
+       }
+       if (*path == '/') {
+               new_path = strdup(path);
+               if (!new_path) {
+                       goto end;
+               }
+               /* Takes ownership of new_path. */
+               new_handle = _lttng_directory_handle_create(new_path);
+               new_path = NULL;
+               goto end;
+       }
+
+       add_trailing_slash = path[path_len - 1] != '/';
+
+       handle_path_len = strlen(ref_handle->base_path) + path_len +
+                       !!add_trailing_slash;
+       if (handle_path_len >= LTTNG_PATH_MAX) {
+               ERR("Failed to initialize directory handle as the resulting path's length (%zu bytes) exceeds the maximal allowed length (%d bytes)",
+                               handle_path_len, LTTNG_PATH_MAX);
+               goto end;
+       }
+       new_path = zmalloc(handle_path_len);
+       if (!new_path) {
+               PERROR("Failed to initialize directory handle");
+               goto end;
+       }
+
+       ret = sprintf(new_handle->base_path, "%s%s%s",
+                       ref_handle->base_path,
+                       path,
+                       add_trailing_slash ? "/" : "");
+       if (ret == -1 || ret >= handle_path_len) {
+               ERR("Failed to initialize directory handle: path formatting failed");
+               goto end;
+       }
+       new_handle = _lttng_directory_handle_create(new_path);
+       new_path = NULL;
+end:
+       free(new_path);
+       return new_handle;
+}
+
+struct lttng_directory_handle *lttng_directory_handle_create_from_dirfd(
+               int dirfd)
+{
+       LTTNG_ASSERT(dirfd == AT_FDCWD);
+       return lttng_directory_handle_create(NULL);
+}
+
+static
+void lttng_directory_handle_release(struct urcu_ref *ref)
+{
+       struct lttng_directory_handle *handle =
+                       container_of(ref, struct lttng_directory_handle, ref);
+
+       free(handle->base_path);
+       lttng_directory_handle_invalidate(handle);
+       free(handle);
+}
+
+struct lttng_directory_handle *lttng_directory_handle_copy(
+               const struct lttng_directory_handle *handle)
+{
+       struct lttng_directory_handle *new_handle = NULL;
+       char *new_path = NULL;
+
+       if (handle->base_path) {
+               new_path = strdup(handle->base_path);
+               if (!new_path) {
+                       goto end;
+               }
+       }
+       new_handle = _lttng_directory_handle_create(new_path);
+end:
+       return new_handle;
+}
+
+bool lttng_directory_handle_equals(const struct lttng_directory_handle *lhs,
+               const struct lttng_directory_handle *rhs)
+{
+       return strcmp(lhs->base_path, rhs->base_path) == 0;
+}
+
+static
+void lttng_directory_handle_invalidate(struct lttng_directory_handle *handle)
+{
+       handle->base_path = NULL;
+}
+
+int lttng_directory_handle_stat(const struct lttng_directory_handle *handle,
+               const char *subdirectory, struct stat *st)
+{
+       int ret;
+       char fullpath[LTTNG_PATH_MAX];
+
+       ret = get_full_path(handle, subdirectory, fullpath, sizeof(fullpath));
+       if (ret) {
+               errno = ENOMEM;
+               goto end;
+       }
+
+       ret = stat(fullpath, st);
+end:
+       return ret;
+}
+
+bool lttng_directory_handle_uses_fd(
+               const struct lttng_directory_handle *handle)
+{
+       return false;
+}
+
+static
+int lttng_directory_handle_mkdir(const struct lttng_directory_handle *handle,
+               const char *subdirectory, mode_t mode)
+{
+       int ret;
+       char fullpath[LTTNG_PATH_MAX];
+
+       ret = get_full_path(handle, subdirectory, fullpath, sizeof(fullpath));
+       if (ret) {
+               errno = ENOMEM;
+               goto end;
+       }
+
+       ret = mkdir(fullpath, mode);
+end:
+       return ret;
+}
+
+static
+int lttng_directory_handle_open(const struct lttng_directory_handle *handle,
+               const char *filename, int flags, mode_t mode)
+{
+       int ret;
+       char fullpath[LTTNG_PATH_MAX];
+
+       ret = get_full_path(handle, filename, fullpath, sizeof(fullpath));
+       if (ret) {
+               errno = ENOMEM;
+               goto end;
+       }
+
+       ret = open(fullpath, flags, mode);
+end:
+       return ret;
+}
+
+static
+int lttng_directory_handle_unlink(
+               const struct lttng_directory_handle *handle,
+               const char *filename)
+{
+       int ret;
+       char fullpath[LTTNG_PATH_MAX];
+
+       ret = get_full_path(handle, filename, fullpath, sizeof(fullpath));
+       if (ret) {
+               errno = ENOMEM;
+               goto end;
+       }
+
+       ret = unlink(fullpath);
+end:
+       return ret;
+}
+
+static
+int _run_as_mkdir(const struct lttng_directory_handle *handle, const char *path,
+               mode_t mode, uid_t uid, gid_t gid)
+{
+       int ret;
+       char fullpath[LTTNG_PATH_MAX];
+
+       ret = get_full_path(handle, path, fullpath, sizeof(fullpath));
+       if (ret) {
+               errno = ENOMEM;
+               goto end;
+       }
+
+       ret = run_as_mkdir(fullpath, mode, uid, gid);
+end:
+       return ret;
+}
+
+static
+int _run_as_open(const struct lttng_directory_handle *handle,
+               const char *filename,
+               int flags, mode_t mode, uid_t uid, gid_t gid)
+{
+       int ret;
+       char fullpath[LTTNG_PATH_MAX];
+
+       ret = get_full_path(handle, filename, fullpath, sizeof(fullpath));
+       if (ret) {
+               errno = ENOMEM;
+               goto end;
+       }
+
+       ret = run_as_open(fullpath, flags, mode, uid, gid);
+end:
+       return ret;
+}
+
+static
+int _run_as_unlink(const struct lttng_directory_handle *handle,
+               const char *filename, uid_t uid, gid_t gid)
+{
+       int ret;
+       char fullpath[LTTNG_PATH_MAX];
+
+       ret = get_full_path(handle, filename, fullpath, sizeof(fullpath));
+       if (ret) {
+               errno = ENOMEM;
+               goto end;
+       }
+
+       ret = run_as_unlink(fullpath, uid, gid);
+end:
+       return ret;
+}
+
+static
+int _run_as_mkdir_recursive(const struct lttng_directory_handle *handle,
+               const char *path, mode_t mode, uid_t uid, gid_t gid)
+{
+       int ret;
+       char fullpath[LTTNG_PATH_MAX];
+
+       ret = get_full_path(handle, path, fullpath, sizeof(fullpath));
+       if (ret) {
+               errno = ENOMEM;
+               goto end;
+       }
+
+       ret = run_as_mkdir_recursive(fullpath, mode, uid, gid);
+end:
+       return ret;
+}
+
+static
+int _lttng_directory_handle_rename(
+               const struct lttng_directory_handle *old_handle,
+               const char *old_name,
+               const struct lttng_directory_handle *new_handle,
+               const char *new_name)
+{
+       int ret;
+       char old_fullpath[LTTNG_PATH_MAX];
+       char new_fullpath[LTTNG_PATH_MAX];
+
+       ret = get_full_path(old_handle, old_name, old_fullpath,
+                       sizeof(old_fullpath));
+       if (ret) {
+               errno = ENOMEM;
+               goto end;
+       }
+       ret = get_full_path(new_handle, new_name, new_fullpath,
+                       sizeof(new_fullpath));
+       if (ret) {
+               errno = ENOMEM;
+               goto end;
+       }
+
+       ret = rename(old_fullpath, new_fullpath);
+end:
+       return ret;
+}
+
+static
+int _run_as_rename(const struct lttng_directory_handle *old_handle,
+               const char *old_name,
+               const struct lttng_directory_handle *new_handle,
+               const char *new_name, uid_t uid, gid_t gid)
+{
+       int ret;
+       char old_fullpath[LTTNG_PATH_MAX];
+       char new_fullpath[LTTNG_PATH_MAX];
+
+       ret = get_full_path(old_handle, old_name, old_fullpath,
+                       sizeof(old_fullpath));
+       if (ret) {
+               errno = ENOMEM;
+               goto end;
+       }
+       ret = get_full_path(new_handle, new_name, new_fullpath,
+                       sizeof(new_fullpath));
+       if (ret) {
+               errno = ENOMEM;
+               goto end;
+       }
+
+       ret = run_as_rename(old_fullpath, new_fullpath, uid, gid);
+end:
+       return ret;
+}
+
+static
+DIR *lttng_directory_handle_opendir(const struct lttng_directory_handle *handle,
+               const char *path)
+{
+       int ret;
+       DIR *dir_stream = NULL;
+       char fullpath[LTTNG_PATH_MAX];
+
+       ret = get_full_path(handle, path, fullpath, sizeof(fullpath));
+       if (ret) {
+               errno = ENOMEM;
+               goto end;
+       }
+
+       dir_stream = opendir(fullpath);
+end:
+       return dir_stream;
+}
+
+static
+int lttng_directory_handle_rmdir(
+               const struct lttng_directory_handle *handle, const char *name)
+{
+       int ret;
+       char fullpath[LTTNG_PATH_MAX];
+
+       ret = get_full_path(handle, name, fullpath, sizeof(fullpath));
+       if (ret) {
+               errno = ENOMEM;
+               goto end;
+       }
+
+       ret = rmdir(fullpath);
+end:
+       return ret;
+}
+
+static
+int _run_as_rmdir(const struct lttng_directory_handle *handle,
+               const char *name, uid_t uid, gid_t gid)
+{
+       int ret;
+       char fullpath[LTTNG_PATH_MAX];
+
+       ret = get_full_path(handle, name, fullpath, sizeof(fullpath));
+       if (ret) {
+               errno = ENOMEM;
+               goto end;
+       }
+
+       ret = run_as_rmdir(fullpath, uid, gid);
+end:
+       return ret;
+}
+
+static
+int _run_as_rmdir_recursive(
+               const struct lttng_directory_handle *handle, const char *name,
+               uid_t uid, gid_t gid, int flags)
+{
+       int ret;
+       char fullpath[LTTNG_PATH_MAX];
+
+       ret = get_full_path(handle, name, fullpath, sizeof(fullpath));
+       if (ret) {
+               errno = ENOMEM;
+               goto end;
+       }
+
+       ret = run_as_rmdir_recursive(fullpath, uid, gid, flags);
+end:
+       return ret;
+}
+
+#endif /* HAVE_DIRFD */
+
+/* Common implementation. */
+
+/*
+ * On some filesystems (e.g. nfs), mkdir will validate access rights before
+ * checking for the existence of the path element. This means that on a setup
+ * where "/home/" is a mounted NFS share, and running as an unpriviledged user,
+ * recursively creating a path of the form "/home/my_user/trace/" will fail with
+ * EACCES on mkdir("/home", ...).
+ *
+ * Checking the path for existence allows us to work around this behaviour.
+ */
+static
+int create_directory_check_exists(const struct lttng_directory_handle *handle,
+               const char *path, mode_t mode)
+{
+       int ret = 0;
+       struct stat st;
+
+       ret = lttng_directory_handle_stat(handle, path, &st);
+       if (ret == 0) {
+               if (S_ISDIR(st.st_mode)) {
+                       /* Directory exists, skip. */
+                       goto end;
+               } else {
+                       /* Exists, but is not a directory. */
+                       errno = ENOTDIR;
+                       ret = -1;
+                       goto end;
+               }
+       } else if (errno != ENOENT) {
+               goto end;
+       }
+
+       /*
+        * Let mkdir handle other errors as the caller expects mkdir
+        * semantics.
+        */
+       ret = lttng_directory_handle_mkdir(handle, path, mode);
+end:
+       return ret;
+}
+
+static
+int create_directory_recursive(const struct lttng_directory_handle *handle,
+               const char *path, mode_t mode)
+{
+       char *p, tmp[LTTNG_PATH_MAX];
+       size_t len;
+       int ret;
+
+       LTTNG_ASSERT(path);
+
+       ret = lttng_strncpy(tmp, path, sizeof(tmp));
+       if (ret) {
+               ERR("Failed to create directory: provided path's length (%zu bytes) exceeds the maximal allowed length (%zu bytes)",
+                               strlen(path) + 1, sizeof(tmp));
+               goto error;
+       }
+
+       len = strlen(path);
+       if (tmp[len - 1] == '/') {
+               tmp[len - 1] = 0;
+       }
+
+       for (p = tmp + 1; *p; p++) {
+               if (*p == '/') {
+                       *p = 0;
+                       if (tmp[strlen(tmp) - 1] == '.' &&
+                                       tmp[strlen(tmp) - 2] == '.' &&
+                                       tmp[strlen(tmp) - 3] == '/') {
+                               ERR("Using '/../' is not permitted in the trace path (%s)",
+                                               tmp);
+                               ret = -1;
+                               goto error;
+                       }
+                       ret = create_directory_check_exists(handle, tmp, mode);
+                       if (ret < 0) {
+                               if (errno != EACCES) {
+                                       PERROR("Failed to create directory \"%s\"",
+                                                       path);
+                                       ret = -errno;
+                                       goto error;
+                               }
+                       }
+                       *p = '/';
+               }
+       }
+
+       ret = create_directory_check_exists(handle, tmp, mode);
+       if (ret < 0) {
+               PERROR("mkdirat recursive last element");
+               ret = -errno;
+       }
+error:
+       return ret;
+}
+
+bool lttng_directory_handle_get(struct lttng_directory_handle *handle)
+{
+       return urcu_ref_get_unless_zero(&handle->ref);
+}
+
+void lttng_directory_handle_put(struct lttng_directory_handle *handle)
+{
+       if (!handle) {
+               return;
+       }
+       LTTNG_ASSERT(handle->ref.refcount);
+       urcu_ref_put(&handle->ref, lttng_directory_handle_release);
+}
+
+int lttng_directory_handle_create_subdirectory_as_user(
+               const struct lttng_directory_handle *handle,
+               const char *subdirectory,
+               mode_t mode, const struct lttng_credentials *creds)
+{
+       int ret;
+
+       if (!creds) {
+               /* Run as current user. */
+               ret = create_directory_check_exists(handle,
+                               subdirectory, mode);
+       } else {
+               ret = _run_as_mkdir(handle, subdirectory, mode,
+                               lttng_credentials_get_uid(creds),
+                               lttng_credentials_get_gid(creds));
+       }
+
+       return ret;
+}
+
+int lttng_directory_handle_create_subdirectory_recursive_as_user(
+               const struct lttng_directory_handle *handle,
+               const char *subdirectory_path,
+               mode_t mode, const struct lttng_credentials *creds)
+{
+       int ret;
+
+       if (!creds) {
+               /* Run as current user. */
+               ret = create_directory_recursive(handle,
+                               subdirectory_path, mode);
+       } else {
+               ret = _run_as_mkdir_recursive(handle, subdirectory_path,
+                               mode, lttng_credentials_get_uid(creds), lttng_credentials_get_gid(creds));
+       }
+
+       return ret;
+}
+
+int lttng_directory_handle_create_subdirectory(
+               const struct lttng_directory_handle *handle,
+               const char *subdirectory,
+               mode_t mode)
+{
+       return lttng_directory_handle_create_subdirectory_as_user(
+                       handle, subdirectory, mode, NULL);
+}
+
+int lttng_directory_handle_create_subdirectory_recursive(
+               const struct lttng_directory_handle *handle,
+               const char *subdirectory_path,
+               mode_t mode)
+{
+       return lttng_directory_handle_create_subdirectory_recursive_as_user(
+                       handle, subdirectory_path, mode, NULL);
+}
+
+int lttng_directory_handle_open_file_as_user(
+               const struct lttng_directory_handle *handle,
+               const char *filename,
+               int flags, mode_t mode,
+               const struct lttng_credentials *creds)
+{
+       int ret;
+
+       if (!creds) {
+               /* Run as current user. */
+               ret = lttng_directory_handle_open(handle, filename, flags,
+                               mode);
+       } else {
+               ret = _run_as_open(handle, filename, flags, mode,
+                               lttng_credentials_get_uid(creds), lttng_credentials_get_gid(creds));
+       }
+       return ret;
+}
+
+int lttng_directory_handle_open_file(
+               const struct lttng_directory_handle *handle,
+               const char *filename,
+               int flags, mode_t mode)
+{
+       return lttng_directory_handle_open_file_as_user(handle, filename, flags,
+                       mode, NULL);
+}
+
+int lttng_directory_handle_unlink_file_as_user(
+               const struct lttng_directory_handle *handle,
+               const char *filename,
+               const struct lttng_credentials *creds)
+{
+       int ret;
+
+       if (!creds) {
+               /* Run as current user. */
+               ret = lttng_directory_handle_unlink(handle, filename);
+       } else {
+               ret = _run_as_unlink(handle, filename, lttng_credentials_get_uid(creds), lttng_credentials_get_gid(creds));
+       }
+       return ret;
+}
+
+int lttng_directory_handle_unlink_file(
+               const struct lttng_directory_handle *handle,
+               const char *filename)
+{
+       return lttng_directory_handle_unlink_file_as_user(handle,
+                       filename, NULL);
+}
+
+int lttng_directory_handle_rename(
+               const struct lttng_directory_handle *old_handle,
+               const char *old_name,
+               const struct lttng_directory_handle *new_handle,
+               const char *new_name)
+{
+       return lttng_directory_handle_rename_as_user(old_handle, old_name,
+                       new_handle, new_name, NULL);
+}
+
+int lttng_directory_handle_rename_as_user(
+               const struct lttng_directory_handle *old_handle,
+               const char *old_name,
+               const struct lttng_directory_handle *new_handle,
+               const char *new_name,
+               const struct lttng_credentials *creds)
+{
+       int ret;
+
+       if (!creds) {
+               /* Run as current user. */
+               ret = _lttng_directory_handle_rename(old_handle,
+                               old_name, new_handle, new_name);
+       } else {
+               ret = _run_as_rename(old_handle, old_name, new_handle,
+                               new_name, lttng_credentials_get_uid(creds), lttng_credentials_get_gid(creds));
+       }
+       return ret;
+}
+
+int lttng_directory_handle_remove_subdirectory(
+               const struct lttng_directory_handle *handle,
+               const char *name)
+{
+       return lttng_directory_handle_remove_subdirectory_as_user(handle, name,
+                       NULL);
+}
+
+int lttng_directory_handle_remove_subdirectory_as_user(
+               const struct lttng_directory_handle *handle,
+               const char *name,
+               const struct lttng_credentials *creds)
+{
+       int ret;
+
+       if (!creds) {
+               /* Run as current user. */
+               ret = lttng_directory_handle_rmdir(handle, name);
+       } else {
+               ret = _run_as_rmdir(handle, name, lttng_credentials_get_uid(creds), lttng_credentials_get_gid(creds));
+       }
+       return ret;
+}
+
+struct rmdir_frame {
+       ssize_t parent_frame_idx;
+       DIR *dir;
+       bool empty;
+       /* Size including '\0'. */
+       size_t path_size;
+};
+
+static
+void rmdir_frame_fini(void *data)
+{
+       int ret;
+       struct rmdir_frame *frame = (rmdir_frame *) data;
+
+       ret = closedir(frame->dir);
+       if (ret == -1) {
+               PERROR("Failed to close directory stream");
+       }
+}
+
+static
+int remove_directory_recursive(const struct lttng_directory_handle *handle,
+               const char *path, int flags)
+{
+       int ret;
+       struct lttng_dynamic_array frames;
+       size_t current_frame_idx = 0;
+       struct rmdir_frame initial_frame = {
+               .parent_frame_idx = -1,
+               .dir = lttng_directory_handle_opendir(handle, path),
+               .empty = true,
+               .path_size = strlen(path) + 1,
+       };
+       struct lttng_dynamic_buffer current_path;
+       const char separator = '/';
+
+       lttng_dynamic_buffer_init(&current_path);
+       lttng_dynamic_array_init(&frames, sizeof(struct rmdir_frame),
+                       rmdir_frame_fini);
+
+       if (flags & ~(LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG |
+                                   LTTNG_DIRECTORY_HANDLE_FAIL_NON_EMPTY_FLAG)) {
+               ERR("Unknown flags %d", flags);
+               ret = -1;
+               goto end;
+       }
+
+       if (!initial_frame.dir) {
+               if (flags & LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG &&
+                               errno == ENOENT) {
+                       DBG("Cannot rmdir \"%s\": root does not exist", path);
+                       ret = 0;
+                       goto end;
+               } else {
+                       PERROR("Failed to rmdir \"%s\"", path);
+                       ret = -1;
+                       goto end;
+               }
+       }
+
+       ret = lttng_dynamic_array_add_element(&frames, &initial_frame);
+       if (ret) {
+               ERR("Failed to push context frame during recursive directory removal");
+               rmdir_frame_fini(&initial_frame);
+               goto end;
+       }
+
+       ret = lttng_dynamic_buffer_append(
+                       &current_path, path, initial_frame.path_size);
+       if (ret) {
+               ERR("Failed to set initial path during recursive directory removal");
+               ret = -1;
+               goto end;
+       }
+
+       while (lttng_dynamic_array_get_count(&frames) > 0) {
+               struct dirent *entry;
+               struct rmdir_frame *current_frame =
+                               (rmdir_frame *) lttng_dynamic_array_get_element(
+                                               &frames, current_frame_idx);
+
+               LTTNG_ASSERT(current_frame->dir);
+               ret = lttng_dynamic_buffer_set_size(
+                               &current_path, current_frame->path_size);
+               LTTNG_ASSERT(!ret);
+               current_path.data[current_path.size - 1] = '\0';
+
+               while ((entry = readdir(current_frame->dir))) {
+                       struct stat st;
+
+                       if (!strcmp(entry->d_name, ".") ||
+                                       !strcmp(entry->d_name, "..")) {
+                               continue;
+                       }
+
+                       /* Set current_path to the entry's path. */
+                       ret = lttng_dynamic_buffer_set_size(
+                                       &current_path, current_path.size - 1);
+                       LTTNG_ASSERT(!ret);
+                       ret = lttng_dynamic_buffer_append(&current_path,
+                                       &separator, sizeof(separator));
+                       if (ret) {
+                               goto end;
+                       }
+                       ret = lttng_dynamic_buffer_append(&current_path,
+                                       entry->d_name,
+                                       strlen(entry->d_name) + 1);
+                       if (ret) {
+                               goto end;
+                       }
+
+                       if (lttng_directory_handle_stat(
+                                           handle, current_path.data, &st)) {
+                               if ((flags & LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG) &&
+                                               errno == ENOENT) {
+                                       break;
+                               }
+                               PERROR("Failed to stat \"%s\"",
+                                               current_path.data);
+                               ret = -1;
+                               goto end;
+                       }
+
+                       if (!S_ISDIR(st.st_mode)) {
+                               if (flags & LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG) {
+                                       current_frame->empty = false;
+                                       break;
+                               } else {
+                                       /* Not empty, abort. */
+                                       DBG("Directory \"%s\" is not empty; refusing to remove directory",
+                                                       current_path.data);
+                                       ret = -1;
+                                       goto end;
+                               }
+                       } else {
+                               struct rmdir_frame new_frame = {
+                                       .parent_frame_idx = (ssize_t) current_frame_idx,
+                                       .dir = lttng_directory_handle_opendir(
+                                                       handle,
+                                                       current_path.data),
+                                       .empty = true,
+                                       .path_size = current_path.size,
+                               };
+
+                               if (!new_frame.dir) {
+                                       if (flags & LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG &&
+                                                       errno == ENOENT) {
+                                               DBG("Non-existing directory stream during recursive directory removal");
+                                               break;
+                                       } else {
+                                               PERROR("Failed to open directory stream during recursive directory removal");
+                                               ret = -1;
+                                               goto end;
+                                       }
+                               }
+                               ret = lttng_dynamic_array_add_element(
+                                               &frames, &new_frame);
+                               if (ret) {
+                                       ERR("Failed to push context frame during recursive directory removal");
+                                       rmdir_frame_fini(&new_frame);
+                                       goto end;
+                               }
+                               current_frame_idx++;
+                               /* We break iteration on readdir. */
+                               break;
+                       }
+               }
+               if (entry) {
+                       continue;
+               }
+
+               /* Pop rmdir frame. */
+               if (current_frame->empty) {
+                       ret = lttng_directory_handle_rmdir(
+                                       handle, current_path.data);
+                       if (ret) {
+                               if ((flags & LTTNG_DIRECTORY_HANDLE_FAIL_NON_EMPTY_FLAG) ||
+                                               errno != ENOENT) {
+                                       PERROR("Failed to remove \"%s\" during recursive directory removal",
+                                                       current_path.data);
+                                       goto end;
+                               }
+                               DBG("Non-existing directory stream during recursive directory removal");
+                       }
+               } else if (current_frame->parent_frame_idx >= 0) {
+                       struct rmdir_frame *parent_frame;
+
+                       parent_frame = (rmdir_frame *) lttng_dynamic_array_get_element(&frames,
+                                       current_frame->parent_frame_idx);
+                       LTTNG_ASSERT(parent_frame);
+                       parent_frame->empty = false;
+               }
+               ret = lttng_dynamic_array_remove_element(
+                               &frames, current_frame_idx);
+               if (ret) {
+                       ERR("Failed to pop context frame during recursive directory removal");
+                       goto end;
+               }
+               current_frame_idx--;
+       }
+end:
+       lttng_dynamic_array_reset(&frames);
+       lttng_dynamic_buffer_reset(&current_path);
+       return ret;
+}
+
+int lttng_directory_handle_remove_subdirectory_recursive(
+               const struct lttng_directory_handle *handle,
+               const char *name,
+               int flags)
+{
+       return lttng_directory_handle_remove_subdirectory_recursive_as_user(
+                       handle, name, NULL, flags);
+}
+
+int lttng_directory_handle_remove_subdirectory_recursive_as_user(
+               const struct lttng_directory_handle *handle,
+               const char *name,
+               const struct lttng_credentials *creds,
+               int flags)
+{
+       int ret;
+
+       if (!creds) {
+               /* Run as current user. */
+               ret = remove_directory_recursive(handle, name, flags);
+       } else {
+               ret = _run_as_rmdir_recursive(handle, name, lttng_credentials_get_uid(creds),
+                               lttng_credentials_get_gid(creds), flags);
+       }
+       return ret;
+}
index b18e2f4e76d653b2810e1bd8892edbd9031d1b90..8bbdfe89cc75c122bda2ea7b77db27ca0727ebf6 100644 (file)
 
 #include <common/compat/errno.h>
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #if (defined(__CYGWIN__))
 typedef long long off64_t;
 #endif
@@ -64,4 +68,8 @@ static inline ssize_t splice(int fd_in, loff_t *off_in, int fd_out, loff_t *off_
 #error "Please add support for your OS."
 #endif /* __linux__ , __FreeBSD__, __CYGWIN__, __sun__, __APPLE__ */
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* _COMPAT_FCNTL_H */
diff --git a/src/common/compat/poll.c b/src/common/compat/poll.c
deleted file mode 100644 (file)
index 9da2470..0000000
+++ /dev/null
@@ -1,719 +0,0 @@
-/*
- * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
- * Copyright (C) 2019 Yannick Lamarre <ylamarre@efficios.com>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-#define _LGPL_SOURCE
-#include <stdlib.h>
-#include <stdbool.h>
-
-#include <common/defaults.h>
-#include <common/error.h>
-#include <common/macros.h>
-#include <common/utils.h>
-
-#include "poll.h"
-
-#if HAVE_EPOLL
-
-#include <fcntl.h>
-#include <limits.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-/*
- * Maximum number of fd we can monitor.
- *
- * For epoll(7), /proc/sys/fs/epoll/max_user_watches (since Linux 2.6.28) will
- * be used for the maximum size of the poll set. If this interface is not
- * available, according to the manpage, the max_user_watches value is 1/25 (4%)
- * of the available low memory divided by the registration cost in bytes which
- * is 90 bytes on a 32-bit kernel and 160 bytes on a 64-bit kernel.
- *
- */
-static unsigned int poll_max_size;
-
-/*
- * Resize the epoll events structure of the new size.
- *
- * Return 0 on success or else -1 with the current events pointer untouched.
- */
-static int resize_poll_event(struct lttng_poll_event *events,
-               uint32_t new_size)
-{
-       struct epoll_event *ptr;
-
-       LTTNG_ASSERT(events);
-
-       ptr = realloc(events->events, new_size * sizeof(*ptr));
-       if (ptr == NULL) {
-               PERROR("realloc epoll add");
-               goto error;
-       }
-       if (new_size > events->alloc_size) {
-               /* Zero newly allocated memory */
-               memset(ptr + events->alloc_size, 0,
-                       (new_size - events->alloc_size) * sizeof(*ptr));
-       }
-       events->events = ptr;
-       events->alloc_size = new_size;
-
-       return 0;
-
-error:
-       return -1;
-}
-
-/*
- * Create epoll set and allocate returned events structure.
- */
-int compat_epoll_create(struct lttng_poll_event *events, int size, int flags)
-{
-       int ret;
-
-       if (events == NULL || size <= 0) {
-               goto error;
-       }
-
-       if (!poll_max_size) {
-               if (lttng_poll_set_max_size()) {
-                       goto error;
-               }
-       }
-
-       /* Don't bust the limit here */
-       if (size > poll_max_size) {
-               size = poll_max_size;
-       }
-
-       ret = compat_glibc_epoll_create(size, flags);
-       if (ret < 0) {
-               /* At this point, every error is fatal */
-               PERROR("epoll_create1");
-               goto error;
-       }
-
-       events->epfd = ret;
-
-       /* This *must* be freed by using lttng_poll_free() */
-       events->events = zmalloc(size * sizeof(struct epoll_event));
-       if (events->events == NULL) {
-               PERROR("zmalloc epoll set");
-               goto error_close;
-       }
-
-       events->alloc_size = events->init_size = size;
-       events->nb_fd = 0;
-
-       return 0;
-
-error_close:
-       ret = close(events->epfd);
-       if (ret) {
-               PERROR("close");
-       }
-error:
-       return -1;
-}
-
-/*
- * Add a fd to the epoll set with requesting events.
- */
-int compat_epoll_add(struct lttng_poll_event *events, int fd, uint32_t req_events)
-{
-       int ret;
-       struct epoll_event ev;
-
-       if (events == NULL || events->events == NULL || fd < 0) {
-               ERR("Bad compat epoll add arguments");
-               goto error;
-       }
-
-       /*
-        * Zero struct epoll_event to ensure all representations of its
-        * union are zeroed.
-        */
-       memset(&ev, 0, sizeof(ev));
-       ev.events = req_events;
-       ev.data.fd = fd;
-
-       ret = epoll_ctl(events->epfd, EPOLL_CTL_ADD, fd, &ev);
-       if (ret < 0) {
-               switch (errno) {
-               case EEXIST:
-                       /* If exist, it's OK. */
-                       goto end;
-               case ENOSPC:
-               case EPERM:
-                       /* Print PERROR and goto end not failing. Show must go on. */
-                       PERROR("epoll_ctl ADD");
-                       goto end;
-               default:
-                       PERROR("epoll_ctl ADD fatal");
-                       goto error;
-               }
-       }
-
-       events->nb_fd++;
-
-end:
-       return 0;
-
-error:
-       return -1;
-}
-
-/*
- * Remove a fd from the epoll set.
- */
-int compat_epoll_del(struct lttng_poll_event *events, int fd)
-{
-       int ret;
-
-       if (events == NULL || fd < 0 || events->nb_fd == 0) {
-               goto error;
-       }
-
-       ret = epoll_ctl(events->epfd, EPOLL_CTL_DEL, fd, NULL);
-       if (ret < 0) {
-               switch (errno) {
-               case ENOENT:
-               case EPERM:
-                       /* Print PERROR and goto end not failing. Show must go on. */
-                       PERROR("epoll_ctl DEL");
-                       goto end;
-               default:
-                       PERROR("epoll_ctl DEL fatal");
-                       goto error;
-               }
-       }
-
-       events->nb_fd--;
-
-end:
-       return 0;
-
-error:
-       return -1;
-}
-
-/*
- * Set an fd's events.
- */
-int compat_epoll_mod(struct lttng_poll_event *events, int fd, uint32_t req_events)
-{
-       int ret;
-       struct epoll_event ev;
-
-       if (events == NULL || fd < 0 || events->nb_fd == 0) {
-               goto error;
-       }
-
-       /*
-        * Zero struct epoll_event to ensure all representations of its
-        * union are zeroed.
-        */
-       memset(&ev, 0, sizeof(ev));
-       ev.events = req_events;
-       ev.data.fd = fd;
-
-       ret = epoll_ctl(events->epfd, EPOLL_CTL_MOD, fd, &ev);
-       if (ret < 0) {
-               switch (errno) {
-               case ENOENT:
-               case EPERM:
-                       /* Print PERROR and goto end not failing. Show must go on. */
-                       PERROR("epoll_ctl MOD");
-                       goto end;
-               default:
-                       PERROR("epoll_ctl MOD fatal");
-                       goto error;
-               }
-       }
-
-end:
-       return 0;
-
-error:
-       return -1;
-}
-
-/*
- * Wait on epoll set. This is a blocking call of timeout value.
- */
-int compat_epoll_wait(struct lttng_poll_event *events, int timeout,
-               bool interruptible)
-{
-       int ret;
-       uint32_t new_size;
-
-       if (events == NULL || events->events == NULL) {
-               ERR("Wrong arguments in compat_epoll_wait");
-               goto error;
-       }
-
-       if (events->nb_fd == 0) {
-               errno = EINVAL;
-               return -1;
-       }
-
-       /*
-        * Resize if needed before waiting. We could either expand the array or
-        * shrink it down. It's important to note that after this step, we are
-        * ensured that the events argument of the epoll_wait call will be large
-        * enough to hold every possible returned events.
-        */
-       new_size = 1U << utils_get_count_order_u32(events->nb_fd);
-       if (new_size != events->alloc_size && new_size >= events->init_size) {
-               ret = resize_poll_event(events, new_size);
-               if (ret < 0) {
-                       /* ENOMEM problem at this point. */
-                       goto error;
-               }
-       }
-
-       do {
-               ret = epoll_wait(events->epfd, events->events, events->nb_fd, timeout);
-       } while (!interruptible && ret == -1 && errno == EINTR);
-       if (ret < 0) {
-               if (errno != EINTR) {
-                       PERROR("epoll_wait");
-               }
-               goto error;
-       }
-
-       /*
-        * Since the returned events are set sequentially in the "events" structure
-        * we only need to return the epoll_wait value and iterate over it.
-        */
-       return ret;
-
-error:
-       return -1;
-}
-
-/*
- * Setup poll set maximum size.
- */
-int compat_epoll_set_max_size(void)
-{
-       int ret, fd, retval = 0;
-       ssize_t size_ret;
-       char buf[64];
-
-       fd = open(COMPAT_EPOLL_PROC_PATH, O_RDONLY);
-       if (fd < 0) {
-               /*
-                * Failing on opening [1] is not an error per see. [1] was
-                * introduced in Linux 2.6.28 but epoll is available since
-                * 2.5.44. Hence, goto end and set a default value without
-                * setting an error return value.
-                *
-                * [1] /proc/sys/fs/epoll/max_user_watches
-                */
-               retval = 0;
-               goto end;
-       }
-
-       size_ret = lttng_read(fd, buf, sizeof(buf));
-       /*
-        * Allow reading a file smaller than buf, but keep space for
-        * final \0.
-        */
-       if (size_ret < 0 || size_ret >= sizeof(buf)) {
-               PERROR("read set max size");
-               retval = -1;
-               goto end_read;
-       }
-       buf[size_ret] = '\0';
-       poll_max_size = atoi(buf);
-end_read:
-       ret = close(fd);
-       if (ret) {
-               PERROR("close");
-       }
-end:
-       if (!poll_max_size) {
-               poll_max_size = DEFAULT_POLL_SIZE;
-       }
-       DBG("epoll set max size is %d", poll_max_size);
-       return retval;
-}
-
-#else /* HAVE_EPOLL */
-
-#include <sys/resource.h>
-#include <sys/time.h>
-
-/*
- * Maximum number of fd we can monitor.
- *
- * For poll(2), the max fds must not exceed RLIMIT_NOFILE given by
- * getrlimit(2).
- */
-static unsigned int poll_max_size;
-
-/*
- * Resize the epoll events structure of the new size.
- *
- * Return 0 on success or else -1 with the current events pointer untouched.
- */
-static int resize_poll_event(struct compat_poll_event_array *array,
-               uint32_t new_size)
-{
-       struct pollfd *ptr;
-
-       LTTNG_ASSERT(array);
-
-       /* Refuse to resize the array more than the max size. */
-       if (new_size > poll_max_size) {
-               goto error;
-       }
-
-       ptr = realloc(array->events, new_size * sizeof(*ptr));
-       if (ptr == NULL) {
-               PERROR("realloc epoll add");
-               goto error;
-       }
-       if (new_size > array->alloc_size) {
-               /* Zero newly allocated memory */
-               memset(ptr + array->alloc_size, 0,
-                       (new_size - array->alloc_size) * sizeof(*ptr));
-       }
-       array->events = ptr;
-       array->alloc_size = new_size;
-
-       return 0;
-
-error:
-       return -1;
-}
-
-/*
- * Update events with the current events object.
- */
-static int update_current_events(struct lttng_poll_event *events)
-{
-       int ret;
-       struct compat_poll_event_array *current, *wait;
-
-       LTTNG_ASSERT(events);
-
-       current = &events->current;
-       wait = &events->wait;
-
-       wait->nb_fd = current->nb_fd;
-       if (current->alloc_size != wait->alloc_size) {
-               ret = resize_poll_event(wait, current->alloc_size);
-               if (ret < 0) {
-                       goto error;
-               }
-       }
-       memcpy(wait->events, current->events,
-                       current->nb_fd * sizeof(*current->events));
-
-       /* Update is done. */
-       events->need_update = 0;
-
-       return 0;
-
-error:
-       return -1;
-}
-
-/*
- * Create pollfd data structure.
- */
-int compat_poll_create(struct lttng_poll_event *events, int size)
-{
-       struct compat_poll_event_array *current, *wait;
-
-       if (events == NULL || size <= 0) {
-               ERR("Wrong arguments for poll create");
-               goto error;
-       }
-
-       if (!poll_max_size) {
-               if (lttng_poll_set_max_size()) {
-                       goto error;
-               }
-       }
-
-       /* Don't bust the limit here */
-       if (size > poll_max_size) {
-               size = poll_max_size;
-       }
-
-       /* Reset everything before begining the allocation. */
-       memset(events, 0, sizeof(struct lttng_poll_event));
-
-       current = &events->current;
-       wait = &events->wait;
-
-       /* This *must* be freed by using lttng_poll_free() */
-       wait->events = zmalloc(size * sizeof(struct pollfd));
-       if (wait->events == NULL) {
-               PERROR("zmalloc struct pollfd");
-               goto error;
-       }
-
-       wait->alloc_size = wait->init_size = size;
-
-       current->events = zmalloc(size * sizeof(struct pollfd));
-       if (current->events == NULL) {
-               PERROR("zmalloc struct current pollfd");
-               goto error;
-       }
-
-       current->alloc_size = current->init_size = size;
-
-       return 0;
-
-error:
-       return -1;
-}
-
-/*
- * Add fd to pollfd data structure with requested events.
- */
-int compat_poll_add(struct lttng_poll_event *events, int fd,
-               uint32_t req_events)
-{
-       int new_size, ret, i;
-       struct compat_poll_event_array *current;
-
-       if (events == NULL || events->current.events == NULL || fd < 0) {
-               ERR("Bad compat poll add arguments");
-               goto error;
-       }
-
-       current = &events->current;
-
-       /* Check if fd we are trying to add is already there. */
-       for (i = 0; i < current->nb_fd; i++) {
-               if (current->events[i].fd == fd) {
-                       errno = EEXIST;
-                       goto error;
-               }
-       }
-
-       /* Resize array if needed. */
-       new_size = 1U << utils_get_count_order_u32(current->nb_fd + 1);
-       if (new_size != current->alloc_size && new_size >= current->init_size) {
-               ret = resize_poll_event(current, new_size);
-               if (ret < 0) {
-                       goto error;
-               }
-       }
-
-       current->events[current->nb_fd].fd = fd;
-       current->events[current->nb_fd].events = req_events;
-       current->nb_fd++;
-       events->need_update = 1;
-
-       DBG("fd %d of %d added to pollfd", fd, current->nb_fd);
-
-       return 0;
-
-error:
-       return -1;
-}
-
-/*
- * Modify an fd's events..
- */
-int compat_poll_mod(struct lttng_poll_event *events, int fd,
-               uint32_t req_events)
-{
-       int i;
-       struct compat_poll_event_array *current;
-
-       if (events == NULL || events->current.nb_fd == 0 ||
-                       events->current.events == NULL || fd < 0) {
-               ERR("Bad compat poll mod arguments");
-               goto error;
-       }
-
-       current = &events->current;
-
-       for (i = 0; i < current->nb_fd; i++) {
-               if (current->events[i].fd == fd) {
-                       current->events[i].events = req_events;
-                       events->need_update = 1;
-                       break;
-               }
-       }
-
-       /*
-        * The epoll flavor doesn't flag modifying a non-included FD as an
-        * error.
-        */
-
-       return 0;
-
-error:
-       return -1;
-}
-
-/*
- * Remove a fd from the pollfd structure.
- */
-int compat_poll_del(struct lttng_poll_event *events, int fd)
-{
-       int i, count = 0, ret;
-       uint32_t new_size;
-       struct compat_poll_event_array *current;
-
-       if (events == NULL || events->current.nb_fd == 0 ||
-                       events->current.events == NULL || fd < 0) {
-               goto error;
-       }
-
-       /* Ease our life a bit. */
-       current = &events->current;
-
-       for (i = 0; i < current->nb_fd; i++) {
-               /* Don't put back the fd we want to delete */
-               if (current->events[i].fd != fd) {
-                       current->events[count].fd = current->events[i].fd;
-                       current->events[count].events = current->events[i].events;
-                       count++;
-               }
-       }
-
-       /* The fd was not in our set, return no error as with epoll. */
-       if (current->nb_fd == count) {
-               goto end;
-       }
-
-       /* No fd duplicate should be ever added into array. */
-       LTTNG_ASSERT(current->nb_fd - 1 == count);
-       current->nb_fd = count;
-
-       /* Resize array if needed. */
-       new_size = 1U << utils_get_count_order_u32(current->nb_fd);
-       if (new_size != current->alloc_size && new_size >= current->init_size
-                       && current->nb_fd != 0) {
-               ret = resize_poll_event(current, new_size);
-               if (ret < 0) {
-                       goto error;
-               }
-       }
-
-       events->need_update = 1;
-
-end:
-       return 0;
-
-error:
-       return -1;
-}
-
-/*
- * Wait on poll() with timeout. Blocking call.
- */
-int compat_poll_wait(struct lttng_poll_event *events, int timeout,
-               bool interruptible)
-{
-       int ret, active_fd_count;
-       size_t pos = 0, consecutive_entries = 0, non_idle_pos;
-
-       if (events == NULL || events->current.events == NULL) {
-               ERR("poll wait arguments error");
-               goto error;
-       }
-
-       if (events->current.nb_fd == 0) {
-               /* Return an invalid error to be consistent with epoll. */
-               errno = EINVAL;
-               events->wait.nb_fd = 0;
-               goto error;
-       }
-
-       if (events->need_update) {
-               ret = update_current_events(events);
-               if (ret < 0) {
-                       errno = ENOMEM;
-                       goto error;
-               }
-       }
-
-       do {
-               ret = poll(events->wait.events, events->wait.nb_fd, timeout);
-       } while (!interruptible && ret == -1 && errno == EINTR);
-       if (ret < 0) {
-               if (errno != EINTR) {
-                       PERROR("poll wait");
-               }
-               goto error;
-       }
-
-       active_fd_count = ret;
-
-       /*
-        * Move all active pollfd structs to the beginning of the
-        * array to emulate compat-epoll behaviour.
-        */
-       if (active_fd_count == events->wait.nb_fd) {
-               goto end;
-       }
-
-       while (consecutive_entries != active_fd_count) {
-               struct pollfd *current = &events->wait.events[pos];
-               struct pollfd idle_entry;
-
-               if (current->revents != 0) {
-                       consecutive_entries++;
-                       pos++;
-                       continue;
-               }
-
-               non_idle_pos = pos;
-
-               /* Look for next non-idle entry. */
-               while (events->wait.events[++non_idle_pos].revents == 0);
-
-               /* Swap idle and non-idle entries. */
-               idle_entry = *current;
-               *current = events->wait.events[non_idle_pos];
-               events->wait.events[non_idle_pos] = idle_entry;
-
-               consecutive_entries++;
-               pos++;
-       }
-end:
-       return ret;
-
-error:
-       return -1;
-}
-
-/*
- * Setup poll set maximum size.
- */
-int compat_poll_set_max_size(void)
-{
-       int ret, retval = 0;
-       struct rlimit lim;
-
-       ret = getrlimit(RLIMIT_NOFILE, &lim);
-       if (ret < 0) {
-               PERROR("getrlimit poll RLIMIT_NOFILE");
-               retval = -1;
-               goto end;
-       }
-
-       poll_max_size = lim.rlim_cur;
-end:
-       if (poll_max_size == 0) {
-               poll_max_size = DEFAULT_POLL_SIZE;
-       }
-       DBG("poll set max size set to %u", poll_max_size);
-       return retval;
-}
-
-#endif /* !HAVE_EPOLL */
diff --git a/src/common/compat/poll.cpp b/src/common/compat/poll.cpp
new file mode 100644 (file)
index 0000000..928867f
--- /dev/null
@@ -0,0 +1,719 @@
+/*
+ * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
+ * Copyright (C) 2019 Yannick Lamarre <ylamarre@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#define _LGPL_SOURCE
+#include <stdlib.h>
+#include <stdbool.h>
+
+#include <common/defaults.h>
+#include <common/error.h>
+#include <common/macros.h>
+#include <common/utils.h>
+
+#include "poll.h"
+
+#if HAVE_EPOLL
+
+#include <fcntl.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+/*
+ * Maximum number of fd we can monitor.
+ *
+ * For epoll(7), /proc/sys/fs/epoll/max_user_watches (since Linux 2.6.28) will
+ * be used for the maximum size of the poll set. If this interface is not
+ * available, according to the manpage, the max_user_watches value is 1/25 (4%)
+ * of the available low memory divided by the registration cost in bytes which
+ * is 90 bytes on a 32-bit kernel and 160 bytes on a 64-bit kernel.
+ *
+ */
+static unsigned int poll_max_size;
+
+/*
+ * Resize the epoll events structure of the new size.
+ *
+ * Return 0 on success or else -1 with the current events pointer untouched.
+ */
+static int resize_poll_event(struct lttng_poll_event *events,
+               uint32_t new_size)
+{
+       struct epoll_event *ptr;
+
+       LTTNG_ASSERT(events);
+
+       ptr = (epoll_event *) realloc(events->events, new_size * sizeof(*ptr));
+       if (ptr == NULL) {
+               PERROR("realloc epoll add");
+               goto error;
+       }
+       if (new_size > events->alloc_size) {
+               /* Zero newly allocated memory */
+               memset(ptr + events->alloc_size, 0,
+                       (new_size - events->alloc_size) * sizeof(*ptr));
+       }
+       events->events = ptr;
+       events->alloc_size = new_size;
+
+       return 0;
+
+error:
+       return -1;
+}
+
+/*
+ * Create epoll set and allocate returned events structure.
+ */
+int compat_epoll_create(struct lttng_poll_event *events, int size, int flags)
+{
+       int ret;
+
+       if (events == NULL || size <= 0) {
+               goto error;
+       }
+
+       if (!poll_max_size) {
+               if (lttng_poll_set_max_size()) {
+                       goto error;
+               }
+       }
+
+       /* Don't bust the limit here */
+       if (size > poll_max_size) {
+               size = poll_max_size;
+       }
+
+       ret = compat_glibc_epoll_create(size, flags);
+       if (ret < 0) {
+               /* At this point, every error is fatal */
+               PERROR("epoll_create1");
+               goto error;
+       }
+
+       events->epfd = ret;
+
+       /* This *must* be freed by using lttng_poll_free() */
+       events->events = (epoll_event *) zmalloc(size * sizeof(struct epoll_event));
+       if (events->events == NULL) {
+               PERROR("zmalloc epoll set");
+               goto error_close;
+       }
+
+       events->alloc_size = events->init_size = size;
+       events->nb_fd = 0;
+
+       return 0;
+
+error_close:
+       ret = close(events->epfd);
+       if (ret) {
+               PERROR("close");
+       }
+error:
+       return -1;
+}
+
+/*
+ * Add a fd to the epoll set with requesting events.
+ */
+int compat_epoll_add(struct lttng_poll_event *events, int fd, uint32_t req_events)
+{
+       int ret;
+       struct epoll_event ev;
+
+       if (events == NULL || events->events == NULL || fd < 0) {
+               ERR("Bad compat epoll add arguments");
+               goto error;
+       }
+
+       /*
+        * Zero struct epoll_event to ensure all representations of its
+        * union are zeroed.
+        */
+       memset(&ev, 0, sizeof(ev));
+       ev.events = req_events;
+       ev.data.fd = fd;
+
+       ret = epoll_ctl(events->epfd, EPOLL_CTL_ADD, fd, &ev);
+       if (ret < 0) {
+               switch (errno) {
+               case EEXIST:
+                       /* If exist, it's OK. */
+                       goto end;
+               case ENOSPC:
+               case EPERM:
+                       /* Print PERROR and goto end not failing. Show must go on. */
+                       PERROR("epoll_ctl ADD");
+                       goto end;
+               default:
+                       PERROR("epoll_ctl ADD fatal");
+                       goto error;
+               }
+       }
+
+       events->nb_fd++;
+
+end:
+       return 0;
+
+error:
+       return -1;
+}
+
+/*
+ * Remove a fd from the epoll set.
+ */
+int compat_epoll_del(struct lttng_poll_event *events, int fd)
+{
+       int ret;
+
+       if (events == NULL || fd < 0 || events->nb_fd == 0) {
+               goto error;
+       }
+
+       ret = epoll_ctl(events->epfd, EPOLL_CTL_DEL, fd, NULL);
+       if (ret < 0) {
+               switch (errno) {
+               case ENOENT:
+               case EPERM:
+                       /* Print PERROR and goto end not failing. Show must go on. */
+                       PERROR("epoll_ctl DEL");
+                       goto end;
+               default:
+                       PERROR("epoll_ctl DEL fatal");
+                       goto error;
+               }
+       }
+
+       events->nb_fd--;
+
+end:
+       return 0;
+
+error:
+       return -1;
+}
+
+/*
+ * Set an fd's events.
+ */
+int compat_epoll_mod(struct lttng_poll_event *events, int fd, uint32_t req_events)
+{
+       int ret;
+       struct epoll_event ev;
+
+       if (events == NULL || fd < 0 || events->nb_fd == 0) {
+               goto error;
+       }
+
+       /*
+        * Zero struct epoll_event to ensure all representations of its
+        * union are zeroed.
+        */
+       memset(&ev, 0, sizeof(ev));
+       ev.events = req_events;
+       ev.data.fd = fd;
+
+       ret = epoll_ctl(events->epfd, EPOLL_CTL_MOD, fd, &ev);
+       if (ret < 0) {
+               switch (errno) {
+               case ENOENT:
+               case EPERM:
+                       /* Print PERROR and goto end not failing. Show must go on. */
+                       PERROR("epoll_ctl MOD");
+                       goto end;
+               default:
+                       PERROR("epoll_ctl MOD fatal");
+                       goto error;
+               }
+       }
+
+end:
+       return 0;
+
+error:
+       return -1;
+}
+
+/*
+ * Wait on epoll set. This is a blocking call of timeout value.
+ */
+int compat_epoll_wait(struct lttng_poll_event *events, int timeout,
+               bool interruptible)
+{
+       int ret;
+       uint32_t new_size;
+
+       if (events == NULL || events->events == NULL) {
+               ERR("Wrong arguments in compat_epoll_wait");
+               goto error;
+       }
+
+       if (events->nb_fd == 0) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       /*
+        * Resize if needed before waiting. We could either expand the array or
+        * shrink it down. It's important to note that after this step, we are
+        * ensured that the events argument of the epoll_wait call will be large
+        * enough to hold every possible returned events.
+        */
+       new_size = 1U << utils_get_count_order_u32(events->nb_fd);
+       if (new_size != events->alloc_size && new_size >= events->init_size) {
+               ret = resize_poll_event(events, new_size);
+               if (ret < 0) {
+                       /* ENOMEM problem at this point. */
+                       goto error;
+               }
+       }
+
+       do {
+               ret = epoll_wait(events->epfd, events->events, events->nb_fd, timeout);
+       } while (!interruptible && ret == -1 && errno == EINTR);
+       if (ret < 0) {
+               if (errno != EINTR) {
+                       PERROR("epoll_wait");
+               }
+               goto error;
+       }
+
+       /*
+        * Since the returned events are set sequentially in the "events" structure
+        * we only need to return the epoll_wait value and iterate over it.
+        */
+       return ret;
+
+error:
+       return -1;
+}
+
+/*
+ * Setup poll set maximum size.
+ */
+int compat_epoll_set_max_size(void)
+{
+       int ret, fd, retval = 0;
+       ssize_t size_ret;
+       char buf[64];
+
+       fd = open(COMPAT_EPOLL_PROC_PATH, O_RDONLY);
+       if (fd < 0) {
+               /*
+                * Failing on opening [1] is not an error per see. [1] was
+                * introduced in Linux 2.6.28 but epoll is available since
+                * 2.5.44. Hence, goto end and set a default value without
+                * setting an error return value.
+                *
+                * [1] /proc/sys/fs/epoll/max_user_watches
+                */
+               retval = 0;
+               goto end;
+       }
+
+       size_ret = lttng_read(fd, buf, sizeof(buf));
+       /*
+        * Allow reading a file smaller than buf, but keep space for
+        * final \0.
+        */
+       if (size_ret < 0 || size_ret >= sizeof(buf)) {
+               PERROR("read set max size");
+               retval = -1;
+               goto end_read;
+       }
+       buf[size_ret] = '\0';
+       poll_max_size = atoi(buf);
+end_read:
+       ret = close(fd);
+       if (ret) {
+               PERROR("close");
+       }
+end:
+       if (!poll_max_size) {
+               poll_max_size = DEFAULT_POLL_SIZE;
+       }
+       DBG("epoll set max size is %d", poll_max_size);
+       return retval;
+}
+
+#else /* HAVE_EPOLL */
+
+#include <sys/resource.h>
+#include <sys/time.h>
+
+/*
+ * Maximum number of fd we can monitor.
+ *
+ * For poll(2), the max fds must not exceed RLIMIT_NOFILE given by
+ * getrlimit(2).
+ */
+static unsigned int poll_max_size;
+
+/*
+ * Resize the epoll events structure of the new size.
+ *
+ * Return 0 on success or else -1 with the current events pointer untouched.
+ */
+static int resize_poll_event(struct compat_poll_event_array *array,
+               uint32_t new_size)
+{
+       struct pollfd *ptr;
+
+       LTTNG_ASSERT(array);
+
+       /* Refuse to resize the array more than the max size. */
+       if (new_size > poll_max_size) {
+               goto error;
+       }
+
+       ptr = realloc(array->events, new_size * sizeof(*ptr));
+       if (ptr == NULL) {
+               PERROR("realloc epoll add");
+               goto error;
+       }
+       if (new_size > array->alloc_size) {
+               /* Zero newly allocated memory */
+               memset(ptr + array->alloc_size, 0,
+                       (new_size - array->alloc_size) * sizeof(*ptr));
+       }
+       array->events = ptr;
+       array->alloc_size = new_size;
+
+       return 0;
+
+error:
+       return -1;
+}
+
+/*
+ * Update events with the current events object.
+ */
+static int update_current_events(struct lttng_poll_event *events)
+{
+       int ret;
+       struct compat_poll_event_array *current, *wait;
+
+       LTTNG_ASSERT(events);
+
+       current = &events->current;
+       wait = &events->wait;
+
+       wait->nb_fd = current->nb_fd;
+       if (current->alloc_size != wait->alloc_size) {
+               ret = resize_poll_event(wait, current->alloc_size);
+               if (ret < 0) {
+                       goto error;
+               }
+       }
+       memcpy(wait->events, current->events,
+                       current->nb_fd * sizeof(*current->events));
+
+       /* Update is done. */
+       events->need_update = 0;
+
+       return 0;
+
+error:
+       return -1;
+}
+
+/*
+ * Create pollfd data structure.
+ */
+int compat_poll_create(struct lttng_poll_event *events, int size)
+{
+       struct compat_poll_event_array *current, *wait;
+
+       if (events == NULL || size <= 0) {
+               ERR("Wrong arguments for poll create");
+               goto error;
+       }
+
+       if (!poll_max_size) {
+               if (lttng_poll_set_max_size()) {
+                       goto error;
+               }
+       }
+
+       /* Don't bust the limit here */
+       if (size > poll_max_size) {
+               size = poll_max_size;
+       }
+
+       /* Reset everything before begining the allocation. */
+       memset(events, 0, sizeof(struct lttng_poll_event));
+
+       current = &events->current;
+       wait = &events->wait;
+
+       /* This *must* be freed by using lttng_poll_free() */
+       wait->events = zmalloc(size * sizeof(struct pollfd));
+       if (wait->events == NULL) {
+               PERROR("zmalloc struct pollfd");
+               goto error;
+       }
+
+       wait->alloc_size = wait->init_size = size;
+
+       current->events = zmalloc(size * sizeof(struct pollfd));
+       if (current->events == NULL) {
+               PERROR("zmalloc struct current pollfd");
+               goto error;
+       }
+
+       current->alloc_size = current->init_size = size;
+
+       return 0;
+
+error:
+       return -1;
+}
+
+/*
+ * Add fd to pollfd data structure with requested events.
+ */
+int compat_poll_add(struct lttng_poll_event *events, int fd,
+               uint32_t req_events)
+{
+       int new_size, ret, i;
+       struct compat_poll_event_array *current;
+
+       if (events == NULL || events->current.events == NULL || fd < 0) {
+               ERR("Bad compat poll add arguments");
+               goto error;
+       }
+
+       current = &events->current;
+
+       /* Check if fd we are trying to add is already there. */
+       for (i = 0; i < current->nb_fd; i++) {
+               if (current->events[i].fd == fd) {
+                       errno = EEXIST;
+                       goto error;
+               }
+       }
+
+       /* Resize array if needed. */
+       new_size = 1U << utils_get_count_order_u32(current->nb_fd + 1);
+       if (new_size != current->alloc_size && new_size >= current->init_size) {
+               ret = resize_poll_event(current, new_size);
+               if (ret < 0) {
+                       goto error;
+               }
+       }
+
+       current->events[current->nb_fd].fd = fd;
+       current->events[current->nb_fd].events = req_events;
+       current->nb_fd++;
+       events->need_update = 1;
+
+       DBG("fd %d of %d added to pollfd", fd, current->nb_fd);
+
+       return 0;
+
+error:
+       return -1;
+}
+
+/*
+ * Modify an fd's events..
+ */
+int compat_poll_mod(struct lttng_poll_event *events, int fd,
+               uint32_t req_events)
+{
+       int i;
+       struct compat_poll_event_array *current;
+
+       if (events == NULL || events->current.nb_fd == 0 ||
+                       events->current.events == NULL || fd < 0) {
+               ERR("Bad compat poll mod arguments");
+               goto error;
+       }
+
+       current = &events->current;
+
+       for (i = 0; i < current->nb_fd; i++) {
+               if (current->events[i].fd == fd) {
+                       current->events[i].events = req_events;
+                       events->need_update = 1;
+                       break;
+               }
+       }
+
+       /*
+        * The epoll flavor doesn't flag modifying a non-included FD as an
+        * error.
+        */
+
+       return 0;
+
+error:
+       return -1;
+}
+
+/*
+ * Remove a fd from the pollfd structure.
+ */
+int compat_poll_del(struct lttng_poll_event *events, int fd)
+{
+       int i, count = 0, ret;
+       uint32_t new_size;
+       struct compat_poll_event_array *current;
+
+       if (events == NULL || events->current.nb_fd == 0 ||
+                       events->current.events == NULL || fd < 0) {
+               goto error;
+       }
+
+       /* Ease our life a bit. */
+       current = &events->current;
+
+       for (i = 0; i < current->nb_fd; i++) {
+               /* Don't put back the fd we want to delete */
+               if (current->events[i].fd != fd) {
+                       current->events[count].fd = current->events[i].fd;
+                       current->events[count].events = current->events[i].events;
+                       count++;
+               }
+       }
+
+       /* The fd was not in our set, return no error as with epoll. */
+       if (current->nb_fd == count) {
+               goto end;
+       }
+
+       /* No fd duplicate should be ever added into array. */
+       LTTNG_ASSERT(current->nb_fd - 1 == count);
+       current->nb_fd = count;
+
+       /* Resize array if needed. */
+       new_size = 1U << utils_get_count_order_u32(current->nb_fd);
+       if (new_size != current->alloc_size && new_size >= current->init_size
+                       && current->nb_fd != 0) {
+               ret = resize_poll_event(current, new_size);
+               if (ret < 0) {
+                       goto error;
+               }
+       }
+
+       events->need_update = 1;
+
+end:
+       return 0;
+
+error:
+       return -1;
+}
+
+/*
+ * Wait on poll() with timeout. Blocking call.
+ */
+int compat_poll_wait(struct lttng_poll_event *events, int timeout,
+               bool interruptible)
+{
+       int ret, active_fd_count;
+       size_t pos = 0, consecutive_entries = 0, non_idle_pos;
+
+       if (events == NULL || events->current.events == NULL) {
+               ERR("poll wait arguments error");
+               goto error;
+       }
+
+       if (events->current.nb_fd == 0) {
+               /* Return an invalid error to be consistent with epoll. */
+               errno = EINVAL;
+               events->wait.nb_fd = 0;
+               goto error;
+       }
+
+       if (events->need_update) {
+               ret = update_current_events(events);
+               if (ret < 0) {
+                       errno = ENOMEM;
+                       goto error;
+               }
+       }
+
+       do {
+               ret = poll(events->wait.events, events->wait.nb_fd, timeout);
+       } while (!interruptible && ret == -1 && errno == EINTR);
+       if (ret < 0) {
+               if (errno != EINTR) {
+                       PERROR("poll wait");
+               }
+               goto error;
+       }
+
+       active_fd_count = ret;
+
+       /*
+        * Move all active pollfd structs to the beginning of the
+        * array to emulate compat-epoll behaviour.
+        */
+       if (active_fd_count == events->wait.nb_fd) {
+               goto end;
+       }
+
+       while (consecutive_entries != active_fd_count) {
+               struct pollfd *current = &events->wait.events[pos];
+               struct pollfd idle_entry;
+
+               if (current->revents != 0) {
+                       consecutive_entries++;
+                       pos++;
+                       continue;
+               }
+
+               non_idle_pos = pos;
+
+               /* Look for next non-idle entry. */
+               while (events->wait.events[++non_idle_pos].revents == 0);
+
+               /* Swap idle and non-idle entries. */
+               idle_entry = *current;
+               *current = events->wait.events[non_idle_pos];
+               events->wait.events[non_idle_pos] = idle_entry;
+
+               consecutive_entries++;
+               pos++;
+       }
+end:
+       return ret;
+
+error:
+       return -1;
+}
+
+/*
+ * Setup poll set maximum size.
+ */
+int compat_poll_set_max_size(void)
+{
+       int ret, retval = 0;
+       struct rlimit lim;
+
+       ret = getrlimit(RLIMIT_NOFILE, &lim);
+       if (ret < 0) {
+               PERROR("getrlimit poll RLIMIT_NOFILE");
+               retval = -1;
+               goto end;
+       }
+
+       poll_max_size = lim.rlim_cur;
+end:
+       if (poll_max_size == 0) {
+               poll_max_size = DEFAULT_POLL_SIZE;
+       }
+       DBG("poll set max size set to %u", poll_max_size);
+       return retval;
+}
+
+#endif /* !HAVE_EPOLL */
diff --git a/src/common/filter-grammar-test.c b/src/common/filter-grammar-test.c
deleted file mode 100644 (file)
index bd8f2de..0000000
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * filter-grammar-test.c
- *
- * LTTng filter grammar test
- *
- * Copyright 2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- */
-
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdlib.h>
-#include <inttypes.h>
-
-#include <common/compat/errno.h>
-#include <common/bytecode/bytecode.h>
-#include <common/filter/filter-ast.h>
-#include <common/filter/filter-parser.h>
-
-/* For error.h */
-int lttng_opt_quiet = 1;
-int lttng_opt_verbose;
-int lttng_opt_mi;
-
-int main(int argc, char **argv)
-{
-       struct filter_parser_ctx *ctx;
-       int ret;
-       int print_xml = 0, generate_ir = 0, generate_bytecode = 0,
-               print_bytecode = 0;
-       int argidx;
-
-       for (argidx = 1; argidx < argc; argidx++) {
-               if (strcmp(argv[argidx], "-p") == 0)
-                       print_xml = 1;
-               else if (strcmp(argv[argidx], "-i") == 0)
-                       generate_ir = 1;
-               else if (strcmp(argv[argidx], "-b") == 0)
-                       generate_bytecode = 1;
-               else if (strcmp(argv[argidx], "-d") == 0)
-                       filter_parser_debug = 1;
-               else if (strcmp(argv[argidx], "-B") == 0)
-                       print_bytecode = 1;
-       }
-
-       /*
-        * Force generate the bytecode if the user asks to print the bytecode
-        * (can't print it without generating it first).
-        */
-       if (print_bytecode) {
-               generate_bytecode = 1;
-       }
-
-       /*
-        * Force generate the IR if the user asks to generate the bytecode
-        * (the bytecode is generated by visiting the IR).
-        */
-       if (generate_bytecode) {
-               generate_ir = 1;
-       }
-
-       ctx = filter_parser_ctx_alloc(stdin);
-       if (!ctx) {
-               fprintf(stderr, "Error allocating parser\n");
-               goto alloc_error;
-       }
-       ret = filter_parser_ctx_append_ast(ctx);
-       if (ret) {
-               fprintf(stderr, "Parse error\n");
-               goto parse_error;
-       }
-       if (print_xml) {
-               ret = filter_visitor_print_xml(ctx, stdout, 0);
-               if (ret) {
-                       fflush(stdout);
-                       fprintf(stderr, "XML print error\n");
-                       goto parse_error;
-               }
-       }
-       if (generate_ir) {
-               printf("Generating IR... ");
-               fflush(stdout);
-               ret = filter_visitor_ir_generate(ctx);
-               if (ret) {
-                       fprintf(stderr, "Generate IR error\n");
-                       goto parse_error;
-               }
-               printf("done\n");
-
-               printf("Validating IR... ");
-               fflush(stdout);
-               ret = filter_visitor_ir_check_binary_op_nesting(ctx);
-               if (ret) {
-                       goto parse_error;
-               }
-               printf("done\n");
-       }
-       if (generate_bytecode) {
-               printf("Generating bytecode... ");
-               fflush(stdout);
-               ret = filter_visitor_bytecode_generate(ctx);
-               if (ret) {
-                       fprintf(stderr, "Generate bytecode error\n");
-                       goto parse_error;
-               }
-               printf("done\n");
-               printf("Size of bytecode generated: %u bytes.\n",
-                       bytecode_get_len(&ctx->bytecode->b));
-       }
-
-       if (print_bytecode) {
-               unsigned int bytecode_len, len, i;
-
-               len = bytecode_get_len(&ctx->bytecode->b);
-               bytecode_len = ctx->bytecode->b.reloc_table_offset;
-               printf("Bytecode:\n");
-               for (i = 0; i < bytecode_len; i++) {
-                       printf("0x%X ",
-                               ((uint8_t *) ctx->bytecode->b.data)[i]);
-               }
-               printf("\n");
-               printf("Reloc table:\n");
-               for (i = bytecode_len; i < len;) {
-                       printf("{ 0x%X, ",
-                               *(uint16_t *) &ctx->bytecode->b.data[i]);
-                       i += sizeof(uint16_t);
-                       printf("%s } ", &((char *) ctx->bytecode->b.data)[i]);
-                       i += strlen(&((char *) ctx->bytecode->b.data)[i]) + 1;
-               }
-               printf("\n");
-       }
-
-       filter_bytecode_free(ctx);
-       filter_ir_free(ctx);
-       filter_parser_ctx_free(ctx);
-       return 0;
-
-parse_error:
-       filter_bytecode_free(ctx);
-       filter_ir_free(ctx);
-       filter_parser_ctx_free(ctx);
-alloc_error:
-       exit(EXIT_FAILURE);
-}
diff --git a/src/common/filter-grammar-test.cpp b/src/common/filter-grammar-test.cpp
new file mode 100644 (file)
index 0000000..bd8f2de
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * filter-grammar-test.c
+ *
+ * LTTng filter grammar test
+ *
+ * Copyright 2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <inttypes.h>
+
+#include <common/compat/errno.h>
+#include <common/bytecode/bytecode.h>
+#include <common/filter/filter-ast.h>
+#include <common/filter/filter-parser.h>
+
+/* For error.h */
+int lttng_opt_quiet = 1;
+int lttng_opt_verbose;
+int lttng_opt_mi;
+
+int main(int argc, char **argv)
+{
+       struct filter_parser_ctx *ctx;
+       int ret;
+       int print_xml = 0, generate_ir = 0, generate_bytecode = 0,
+               print_bytecode = 0;
+       int argidx;
+
+       for (argidx = 1; argidx < argc; argidx++) {
+               if (strcmp(argv[argidx], "-p") == 0)
+                       print_xml = 1;
+               else if (strcmp(argv[argidx], "-i") == 0)
+                       generate_ir = 1;
+               else if (strcmp(argv[argidx], "-b") == 0)
+                       generate_bytecode = 1;
+               else if (strcmp(argv[argidx], "-d") == 0)
+                       filter_parser_debug = 1;
+               else if (strcmp(argv[argidx], "-B") == 0)
+                       print_bytecode = 1;
+       }
+
+       /*
+        * Force generate the bytecode if the user asks to print the bytecode
+        * (can't print it without generating it first).
+        */
+       if (print_bytecode) {
+               generate_bytecode = 1;
+       }
+
+       /*
+        * Force generate the IR if the user asks to generate the bytecode
+        * (the bytecode is generated by visiting the IR).
+        */
+       if (generate_bytecode) {
+               generate_ir = 1;
+       }
+
+       ctx = filter_parser_ctx_alloc(stdin);
+       if (!ctx) {
+               fprintf(stderr, "Error allocating parser\n");
+               goto alloc_error;
+       }
+       ret = filter_parser_ctx_append_ast(ctx);
+       if (ret) {
+               fprintf(stderr, "Parse error\n");
+               goto parse_error;
+       }
+       if (print_xml) {
+               ret = filter_visitor_print_xml(ctx, stdout, 0);
+               if (ret) {
+                       fflush(stdout);
+                       fprintf(stderr, "XML print error\n");
+                       goto parse_error;
+               }
+       }
+       if (generate_ir) {
+               printf("Generating IR... ");
+               fflush(stdout);
+               ret = filter_visitor_ir_generate(ctx);
+               if (ret) {
+                       fprintf(stderr, "Generate IR error\n");
+                       goto parse_error;
+               }
+               printf("done\n");
+
+               printf("Validating IR... ");
+               fflush(stdout);
+               ret = filter_visitor_ir_check_binary_op_nesting(ctx);
+               if (ret) {
+                       goto parse_error;
+               }
+               printf("done\n");
+       }
+       if (generate_bytecode) {
+               printf("Generating bytecode... ");
+               fflush(stdout);
+               ret = filter_visitor_bytecode_generate(ctx);
+               if (ret) {
+                       fprintf(stderr, "Generate bytecode error\n");
+                       goto parse_error;
+               }
+               printf("done\n");
+               printf("Size of bytecode generated: %u bytes.\n",
+                       bytecode_get_len(&ctx->bytecode->b));
+       }
+
+       if (print_bytecode) {
+               unsigned int bytecode_len, len, i;
+
+               len = bytecode_get_len(&ctx->bytecode->b);
+               bytecode_len = ctx->bytecode->b.reloc_table_offset;
+               printf("Bytecode:\n");
+               for (i = 0; i < bytecode_len; i++) {
+                       printf("0x%X ",
+                               ((uint8_t *) ctx->bytecode->b.data)[i]);
+               }
+               printf("\n");
+               printf("Reloc table:\n");
+               for (i = bytecode_len; i < len;) {
+                       printf("{ 0x%X, ",
+                               *(uint16_t *) &ctx->bytecode->b.data[i]);
+                       i += sizeof(uint16_t);
+                       printf("%s } ", &((char *) ctx->bytecode->b.data)[i]);
+                       i += strlen(&((char *) ctx->bytecode->b.data)[i]) + 1;
+               }
+               printf("\n");
+       }
+
+       filter_bytecode_free(ctx);
+       filter_ir_free(ctx);
+       filter_parser_ctx_free(ctx);
+       return 0;
+
+parse_error:
+       filter_bytecode_free(ctx);
+       filter_ir_free(ctx);
+       filter_parser_ctx_free(ctx);
+alloc_error:
+       exit(EXIT_FAILURE);
+}
index e1e538657c821fa625629263df24583e9b59b650..a311bc3e4dc7a40b89c8ddb5b056a89f0eda3e38 100644 (file)
@@ -78,7 +78,7 @@ TESTS += test_ust_data
 endif
 
 # URI unit tests
-test_uri_SOURCES = test_uri.c
+test_uri_SOURCES = test_uri.cpp
 test_uri_LDADD = $(LIBTAP) $(LIBCOMMON) $(LIBHASHTABLE) $(DL_LIBS)
 
 RELAYD_OBJS = $(top_builddir)/src/bin/lttng-relayd/backward-compatibility-group-by.$(OBJEXT)
@@ -103,46 +103,46 @@ test_kernel_data_LDADD = $(LIBTAP) $(LIBLTTNG_SESSIOND_COMMON) $(DL_LIBS)
 # utils suffix for unit test
 
 # parse_size_suffix unit test
-test_utils_parse_size_suffix_SOURCES = test_utils_parse_size_suffix.c
+test_utils_parse_size_suffix_SOURCES = test_utils_parse_size_suffix.cpp
 test_utils_parse_size_suffix_LDADD = $(LIBTAP) $(LIBHASHTABLE) $(LIBCOMMON) $(DL_LIBS)
 
 # parse_time_suffix unit test
-test_utils_parse_time_suffix_SOURCES = test_utils_parse_time_suffix.c
+test_utils_parse_time_suffix_SOURCES = test_utils_parse_time_suffix.cpp
 test_utils_parse_time_suffix_LDADD = $(LIBTAP) $(LIBHASHTABLE) $(LIBCOMMON)
 
 # compat_poll unit test
-test_utils_compat_poll_SOURCES = test_utils_compat_poll.c
+test_utils_compat_poll_SOURCES = test_utils_compat_poll.cpp
 test_utils_compat_poll_LDADD  = $(LIBTAP) $(LIBHASHTABLE) $(DL_LIBS) \
                      $(top_builddir)/src/common/compat/libcompat.la $(LIBCOMMON)
 
 # compat_pthread unit test
-test_utils_compat_pthread_SOURCES = test_utils_compat_pthread.c
+test_utils_compat_pthread_SOURCES = test_utils_compat_pthread.cpp
 test_utils_compat_pthread_LDADD  = $(LIBTAP) \
                      $(top_builddir)/src/common/compat/libcompat.la $(LIBCOMMON)
 
 # expand_path unit test
-test_utils_expand_path_SOURCES = test_utils_expand_path.c
+test_utils_expand_path_SOURCES = test_utils_expand_path.cpp
 test_utils_expand_path_LDADD = $(LIBTAP) $(LIBHASHTABLE) $(LIBCOMMON) $(DL_LIBS)
 
 # directory handle unit test
-test_directory_handle_SOURCES = test_directory_handle.c
+test_directory_handle_SOURCES = test_directory_handle.cpp
 test_directory_handle_LDADD = $(LIBTAP) $(LIBHASHTABLE) $(LIBCOMMON) $(DL_LIBS)
 
 # string utilities unit test
-test_string_utils_SOURCES = test_string_utils.c
+test_string_utils_SOURCES = test_string_utils.cpp
 test_string_utils_LDADD = $(LIBTAP) $(LIBCOMMON) $(LIBSTRINGUTILS) $(DL_LIBS)
 
 # Notification api
-test_notification_SOURCES = test_notification.c
+test_notification_SOURCES = test_notification.cpp
 test_notification_LDADD = $(LIBTAP) $(LIBLTTNG_CTL) $(DL_LIBS)
 
 # Event rule api
-test_event_rule_SOURCES = test_event_rule.c
+test_event_rule_SOURCES = test_event_rule.cpp
 test_event_rule_LDADD = $(LIBTAP) $(LIBCOMMON) $(LIBLTTNG_CTL) $(DL_LIBS) \
                      $(top_builddir)/src/bin/lttng/lttng-loglevel.$(OBJEXT)
 
 # Condition api
-test_condition_SOURCES = test_condition.c
+test_condition_SOURCES = test_condition.cpp
 test_condition_LDADD = $(LIBTAP) $(LIBCOMMON) $(LIBLTTNG_CTL) $(DL_LIBS)
 
 # relayd backward compat for groou-by-session utilities
@@ -151,42 +151,42 @@ test_relayd_backward_compat_group_by_session_LDADD = $(LIBTAP) $(LIBCOMMON) $(RE
 test_relayd_backward_compat_group_by_session_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/src/bin/lttng-relayd
 
 # rate policy object unit test
-test_rate_policy_SOURCES = test_rate_policy.c
+test_rate_policy_SOURCES = test_rate_policy.cpp
 test_rate_policy_LDADD = $(LIBTAP) $(LIBCOMMON) $(LIBLTTNG_CTL) $(DL_LIBS) \
                      $(top_builddir)/src/bin/lttng/lttng-loglevel.$(OBJEXT)
 
 # fd tracker unit test
-test_fd_tracker_SOURCES = test_fd_tracker.c
+test_fd_tracker_SOURCES = test_fd_tracker.cpp
 test_fd_tracker_LDADD = $(LIBTAP) $(LIBFDTRACKER) $(DL_LIBS) $(URCU_LIBS) $(LIBCOMMON) $(LIBHASHTABLE)
 
 # uuid unit test
-test_uuid_SOURCES = test_uuid.c
+test_uuid_SOURCES = test_uuid.cpp
 test_uuid_LDADD = $(LIBTAP) $(LIBCOMMON)
 
 # buffer view unit test
-test_buffer_view_SOURCES = test_buffer_view.c
+test_buffer_view_SOURCES = test_buffer_view.cpp
 test_buffer_view_LDADD = $(LIBTAP) $(LIBCOMMON)
 
 # payload unit test
-test_payload_SOURCES = test_payload.c
+test_payload_SOURCES = test_payload.cpp
 test_payload_LDADD = $(LIBTAP) $(LIBSESSIOND_COMM) $(LIBCOMMON)
 
 # unix socket test
-test_unix_socket_SOURCES = test_unix_socket.c
+test_unix_socket_SOURCES = test_unix_socket.cpp
 test_unix_socket_LDADD = $(LIBTAP) $(LIBSESSIOND_COMM) $(LIBCOMMON)
 
 # Kernel probe location api test
-test_kernel_probe_SOURCES = test_kernel_probe.c
+test_kernel_probe_SOURCES = test_kernel_probe.cpp
 test_kernel_probe_LDADD = $(LIBTAP) $(LIBCOMMON) $(LIBLTTNG_CTL) $(DL_LIBS)
 #
 # Event expression to bytecode test
-test_event_expr_to_bytecode_SOURCES = test_event_expr_to_bytecode.c
+test_event_expr_to_bytecode_SOURCES = test_event_expr_to_bytecode.cpp
 test_event_expr_to_bytecode_LDADD = $(LIBTAP) $(LIBLTTNG_CTL) $(LIBCOMMON)
 
 # Log level rule api
-test_log_level_rule_SOURCES = test_log_level_rule.c
+test_log_level_rule_SOURCES = test_log_level_rule.cpp
 test_log_level_rule_LDADD = $(LIBTAP) $(LIBCOMMON) $(LIBLTTNG_CTL) $(DL_LIBS)
 
 # Action api
-test_action_SOURCES = test_action.c
+test_action_SOURCES = test_action.cpp
 test_action_LDADD = $(LIBTAP) $(LIBCOMMON) $(LIBLTTNG_CTL) $(DL_LIBS)
index 7f15f99c94c2803107ebf23e34449cbe780c3cb0..0039697752bdca6309325a294f7f4ddb97bd6241 100644 (file)
@@ -10,7 +10,7 @@ LIBHASHTABLE=$(top_builddir)/src/common/hashtable/libhashtable.la
 noinst_PROGRAMS = ini_config
 EXTRA_DIST = test_ini_config sample.ini
 
-ini_config_SOURCES = ini_config.c
+ini_config_SOURCES = ini_config.cpp
 ini_config_LDADD = $(LIBTAP) $(LIBCONFIG) $(LIBCOMMON) $(LIBHASHTABLE) \
        $(top_builddir)/src/lib/lttng-ctl/liblttng-ctl.la
 
diff --git a/tests/unit/ini_config/ini_config.c b/tests/unit/ini_config/ini_config.c
deleted file mode 100644 (file)
index 6775ddd..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright (C) 2013 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-#include <tap/tap.h>
-#include <common/config/session-config.h>
-#include <common/utils.h>
-#include <string.h>
-#include <lttng/constant.h>
-
-struct state {
-       int section_1;
-       int section_2;
-       int section_3;
-       int section_global;
-       int text_entry;
-       int int_entry;
-};
-
-int lttng_opt_quiet = 1;
-int lttng_opt_verbose = 0;
-int lttng_opt_mi;
-
-static int entry_handler(const struct config_entry *entry, struct state *state)
-{
-       int ret = 0;
-
-       if (!entry || !state) {
-               ret = -1;
-               goto end;
-       }
-
-       if (!strcmp(entry->section, "section1")) {
-               state->section_1 = 1;
-               if (!strcmp(entry->name, "section1_entry") &&
-                       !strcmp(entry->value, "42")) {
-                       state->int_entry = 1;
-               }
-       }
-
-       if (!strcmp(entry->section, "section2")) {
-               state->section_2 = 1;
-       }
-
-       if (!strcmp(entry->section, "section 3")) {
-               state->section_3 = 1;
-               if (!strcmp(entry->name, "name with a space") &&
-                       !strcmp(entry->value, "another value")) {
-                       state->text_entry = 1;
-               }
-       }
-
-       if (!strcmp(entry->section, "")) {
-               state->section_global = 1;
-       }
-end:
-       return ret;
-}
-
-int main(int argc, char **argv)
-{
-       char *path = NULL;
-       int ret;
-       struct state state = {};
-
-       if (argc < 2) {
-               diag("Usage: path_to_sample_INI_file");
-               goto end;
-       }
-
-       if (strlen(argv[1]) >= LTTNG_PATH_MAX) {
-               diag("The provided path exceeds the maximal permitted length of %i bytes",
-                               LTTNG_PATH_MAX);
-               goto end;
-       }
-       path = utils_expand_path(argv[1]);
-       if (!path) {
-               fail("Failed to resolve sample INI file path");
-       }
-
-       plan_no_plan();
-       ret = config_get_section_entries(path, NULL,
-               (config_entry_handler_cb)entry_handler, &state);
-       ok(ret == 0, "Successfully opened a config file, registered to all sections");
-       ok(state.section_1 && state.section_2 && state.section_3 &&
-               state.section_global, "Processed entries from each sections");
-       ok(state.text_entry, "Text value parsed correctly");
-
-       memset(&state, 0, sizeof(struct state));
-       ret = config_get_section_entries(path, "section1",
-               (config_entry_handler_cb)entry_handler, &state);
-       ok(ret == 0, "Successfully opened a config file, registered to one section");
-       ok(state.section_1 && !state.section_2 && !state.section_3 &&
-               !state.section_global, "Processed an entry from section1 only");
-       ok(state.int_entry, "Int value parsed correctly");
-
-       memset(&state, 0, sizeof(struct state));
-       ret = config_get_section_entries(path, "",
-               (config_entry_handler_cb)entry_handler, &state);
-       ok(ret == 0, "Successfully opened a config file, registered to the global section");
-       ok(!state.section_1 && !state.section_2 && !state.section_3 &&
-               state.section_global, "Processed an entry from the global section only");
-end:
-       free(path);
-       return exit_status();
-}
diff --git a/tests/unit/ini_config/ini_config.cpp b/tests/unit/ini_config/ini_config.cpp
new file mode 100644 (file)
index 0000000..6775ddd
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2013 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#include <tap/tap.h>
+#include <common/config/session-config.h>
+#include <common/utils.h>
+#include <string.h>
+#include <lttng/constant.h>
+
+struct state {
+       int section_1;
+       int section_2;
+       int section_3;
+       int section_global;
+       int text_entry;
+       int int_entry;
+};
+
+int lttng_opt_quiet = 1;
+int lttng_opt_verbose = 0;
+int lttng_opt_mi;
+
+static int entry_handler(const struct config_entry *entry, struct state *state)
+{
+       int ret = 0;
+
+       if (!entry || !state) {
+               ret = -1;
+               goto end;
+       }
+
+       if (!strcmp(entry->section, "section1")) {
+               state->section_1 = 1;
+               if (!strcmp(entry->name, "section1_entry") &&
+                       !strcmp(entry->value, "42")) {
+                       state->int_entry = 1;
+               }
+       }
+
+       if (!strcmp(entry->section, "section2")) {
+               state->section_2 = 1;
+       }
+
+       if (!strcmp(entry->section, "section 3")) {
+               state->section_3 = 1;
+               if (!strcmp(entry->name, "name with a space") &&
+                       !strcmp(entry->value, "another value")) {
+                       state->text_entry = 1;
+               }
+       }
+
+       if (!strcmp(entry->section, "")) {
+               state->section_global = 1;
+       }
+end:
+       return ret;
+}
+
+int main(int argc, char **argv)
+{
+       char *path = NULL;
+       int ret;
+       struct state state = {};
+
+       if (argc < 2) {
+               diag("Usage: path_to_sample_INI_file");
+               goto end;
+       }
+
+       if (strlen(argv[1]) >= LTTNG_PATH_MAX) {
+               diag("The provided path exceeds the maximal permitted length of %i bytes",
+                               LTTNG_PATH_MAX);
+               goto end;
+       }
+       path = utils_expand_path(argv[1]);
+       if (!path) {
+               fail("Failed to resolve sample INI file path");
+       }
+
+       plan_no_plan();
+       ret = config_get_section_entries(path, NULL,
+               (config_entry_handler_cb)entry_handler, &state);
+       ok(ret == 0, "Successfully opened a config file, registered to all sections");
+       ok(state.section_1 && state.section_2 && state.section_3 &&
+               state.section_global, "Processed entries from each sections");
+       ok(state.text_entry, "Text value parsed correctly");
+
+       memset(&state, 0, sizeof(struct state));
+       ret = config_get_section_entries(path, "section1",
+               (config_entry_handler_cb)entry_handler, &state);
+       ok(ret == 0, "Successfully opened a config file, registered to one section");
+       ok(state.section_1 && !state.section_2 && !state.section_3 &&
+               !state.section_global, "Processed an entry from section1 only");
+       ok(state.int_entry, "Int value parsed correctly");
+
+       memset(&state, 0, sizeof(struct state));
+       ret = config_get_section_entries(path, "",
+               (config_entry_handler_cb)entry_handler, &state);
+       ok(ret == 0, "Successfully opened a config file, registered to the global section");
+       ok(!state.section_1 && !state.section_2 && !state.section_3 &&
+               state.section_global, "Processed an entry from the global section only");
+end:
+       free(path);
+       return exit_status();
+}
diff --git a/tests/unit/test_action.c b/tests/unit/test_action.c
deleted file mode 100644 (file)
index ad323e9..0000000
+++ /dev/null
@@ -1,540 +0,0 @@
-/*
- * test_action.c
- *
- * Unit tests for the notification API.
- *
- * Copyright (C) 2017 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
- *
- * SPDX-License-Identifier: MIT
- *
- */
-
-#include <inttypes.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <tap/tap.h>
-
-#include <common/payload-view.h>
-#include <common/payload.h>
-#include <lttng/action/action-internal.h>
-#include <lttng/action/action.h>
-#include <lttng/action/notify.h>
-#include <lttng/action/rate-policy-internal.h>
-#include <lttng/action/rate-policy.h>
-#include <lttng/action/rotate-session.h>
-#include <lttng/action/snapshot-session.h>
-#include <lttng/action/start-session.h>
-#include <lttng/action/stop-session.h>
-
-/* For error.h */
-int lttng_opt_quiet = 1;
-int lttng_opt_verbose;
-int lttng_opt_mi;
-
-#define NUM_TESTS 60
-
-static void test_action_notify(void)
-{
-       int ret;
-       enum lttng_action_status status;
-       struct lttng_action *notify_action = NULL,
-                           *notify_action_from_buffer = NULL;
-       struct lttng_rate_policy *policy = NULL, *default_policy;
-       struct lttng_payload payload;
-
-       lttng_payload_init(&payload);
-
-       /* To set. */
-       policy = lttng_rate_policy_every_n_create(100);
-       /* For comparison. */
-       default_policy = lttng_rate_policy_every_n_create(1);
-
-       LTTNG_ASSERT(policy && default_policy);
-
-       notify_action = lttng_action_notify_create();
-       ok(notify_action, "Create notify action");
-       ok(lttng_action_get_type(notify_action) == LTTNG_ACTION_TYPE_NOTIFY,
-                       "Action has type LTTNG_ACTION_TYPE_NOTIFY");
-
-       /* Validate the default policy for a notify action. */
-       {
-               const struct lttng_rate_policy *cur_policy = NULL;
-               status = lttng_action_notify_get_rate_policy(
-                               notify_action, &cur_policy);
-               ok(status == LTTNG_ACTION_STATUS_OK &&
-                                               lttng_rate_policy_is_equal(
-                                                               default_policy,
-                                                               cur_policy),
-                               "Default policy is every n=1");
-       }
-
-       /* Set a custom policy. */
-       status = lttng_action_notify_set_rate_policy(notify_action, policy);
-       ok(status == LTTNG_ACTION_STATUS_OK, "Set rate policy");
-
-       /* Validate the custom policy for a notify action. */
-       {
-               const struct lttng_rate_policy *cur_policy = NULL;
-               status = lttng_action_notify_get_rate_policy(
-                               notify_action, &cur_policy);
-               ok(status == LTTNG_ACTION_STATUS_OK &&
-                                               lttng_rate_policy_is_equal(
-                                                               policy,
-                                                               cur_policy),
-                               "Notify action policy get");
-       }
-
-       ret = lttng_action_serialize(notify_action, &payload);
-       ok(ret == 0, "Action notify serialized");
-
-       {
-               struct lttng_payload_view view =
-                               lttng_payload_view_from_payload(
-                                               &payload, 0, -1);
-               (void) lttng_action_create_from_payload(
-                               &view, &notify_action_from_buffer);
-       }
-       ok(notify_action_from_buffer,
-                       "Notify action created from payload is non-null");
-
-       ok(lttng_action_is_equal(notify_action, notify_action_from_buffer),
-                       "Serialized and de-serialized notify action are equal");
-
-       lttng_rate_policy_destroy(default_policy);
-       lttng_rate_policy_destroy(policy);
-       lttng_action_destroy(notify_action);
-       lttng_action_destroy(notify_action_from_buffer);
-       lttng_payload_reset(&payload);
-}
-
-static void test_action_rotate_session(void)
-{
-       int ret;
-       enum lttng_action_status status;
-       struct lttng_action *rotate_session_action = NULL,
-                           *rotate_session_action_from_buffer = NULL;
-       struct lttng_rate_policy *policy = NULL, *default_policy;
-       struct lttng_payload payload;
-       const char *session_name = "my_session_name";
-       const char *get_session_name;
-
-       lttng_payload_init(&payload);
-
-       /* To set. */
-       policy = lttng_rate_policy_every_n_create(100);
-       /* For comparison. */
-       default_policy = lttng_rate_policy_every_n_create(1);
-
-       LTTNG_ASSERT(policy && default_policy);
-
-       rotate_session_action = lttng_action_rotate_session_create();
-       ok(rotate_session_action, "Create rotate_session action");
-       ok(lttng_action_get_type(rotate_session_action) ==
-                                       LTTNG_ACTION_TYPE_ROTATE_SESSION,
-                       "Action has type LTTNG_ACTION_TYPE_ROTATE_SESSION");
-
-       /* Session name setter. */
-       status = lttng_action_rotate_session_set_session_name(NULL, NULL);
-       ok(status == LTTNG_ACTION_STATUS_INVALID,
-                       "Set session name (NULL,NULL) expect invalid");
-       status = lttng_action_rotate_session_set_session_name(
-                       rotate_session_action, NULL);
-       ok(status == LTTNG_ACTION_STATUS_INVALID,
-                       "Set session name (object,NULL) expect invalid");
-       status = lttng_action_rotate_session_set_session_name(
-                       NULL, session_name);
-       ok(status == LTTNG_ACTION_STATUS_INVALID,
-                       "Set session name (NULL,object) expect invalid");
-
-       /* Set the session name */
-       status = lttng_action_rotate_session_set_session_name(
-                       rotate_session_action, session_name);
-       ok(status == LTTNG_ACTION_STATUS_OK, "Set session name");
-
-       status = lttng_action_rotate_session_get_session_name(
-                       rotate_session_action, &get_session_name);
-       ok(status == LTTNG_ACTION_STATUS_OK &&
-                                       !strcmp(session_name, get_session_name),
-                       "Get session name, expected `%s` got `%s`",
-                       session_name, get_session_name);
-
-       /* Validate the default policy for a rotate_session action. */
-       {
-               const struct lttng_rate_policy *cur_policy = NULL;
-               status = lttng_action_rotate_session_get_rate_policy(
-                               rotate_session_action, &cur_policy);
-               ok(status == LTTNG_ACTION_STATUS_OK &&
-                                               lttng_rate_policy_is_equal(
-                                                               default_policy,
-                                                               cur_policy),
-                               "Default policy is every n=1");
-       }
-
-       /* Set a custom policy. */
-       status = lttng_action_rotate_session_set_rate_policy(
-                       rotate_session_action, policy);
-       ok(status == LTTNG_ACTION_STATUS_OK, "Set rate policy");
-
-       /* Validate the custom policy for a rotate_session action. */
-       {
-               const struct lttng_rate_policy *cur_policy = NULL;
-               status = lttng_action_rotate_session_get_rate_policy(
-                               rotate_session_action, &cur_policy);
-               ok(status == LTTNG_ACTION_STATUS_OK &&
-                                               lttng_rate_policy_is_equal(
-                                                               policy,
-                                                               cur_policy),
-                               "rotate_session action policy get");
-       }
-
-       /* Ser/des tests. */
-       ret = lttng_action_serialize(rotate_session_action, &payload);
-       ok(ret == 0, "Action rotate_session serialized");
-
-       {
-               struct lttng_payload_view view =
-                               lttng_payload_view_from_payload(
-                                               &payload, 0, -1);
-               (void) lttng_action_create_from_payload(
-                               &view, &rotate_session_action_from_buffer);
-       }
-       ok(rotate_session_action_from_buffer,
-                       "rotate_session action created from payload is non-null");
-
-       ok(lttng_action_is_equal(rotate_session_action,
-                          rotate_session_action_from_buffer),
-                       "Serialized and de-serialized rotate_session action are equal");
-
-       lttng_rate_policy_destroy(default_policy);
-       lttng_rate_policy_destroy(policy);
-       lttng_action_destroy(rotate_session_action);
-       lttng_action_destroy(rotate_session_action_from_buffer);
-       lttng_payload_reset(&payload);
-}
-
-static void test_action_start_session(void)
-{
-       int ret;
-       enum lttng_action_status status;
-       struct lttng_action *start_session_action = NULL,
-                           *start_session_action_from_buffer = NULL;
-       struct lttng_rate_policy *policy = NULL, *default_policy;
-       struct lttng_payload payload;
-       const char *session_name = "my_session_name";
-       const char *get_session_name;
-
-       lttng_payload_init(&payload);
-
-       /* To set. */
-       policy = lttng_rate_policy_every_n_create(100);
-       /* For comparison. */
-       default_policy = lttng_rate_policy_every_n_create(1);
-
-       LTTNG_ASSERT(policy && default_policy);
-
-       start_session_action = lttng_action_start_session_create();
-       ok(start_session_action, "Create start_session action");
-       ok(lttng_action_get_type(start_session_action) ==
-                                       LTTNG_ACTION_TYPE_START_SESSION,
-                       "Action has type LTTNG_ACTION_TYPE_START_SESSION");
-
-       /* Session name setter. */
-       status = lttng_action_start_session_set_session_name(NULL, NULL);
-       ok(status == LTTNG_ACTION_STATUS_INVALID,
-                       "Set session name (NULL,NULL) expect invalid");
-       status = lttng_action_start_session_set_session_name(
-                       start_session_action, NULL);
-       ok(status == LTTNG_ACTION_STATUS_INVALID,
-                       "Set session name (object,NULL) expect invalid");
-       status = lttng_action_start_session_set_session_name(
-                       NULL, session_name);
-       ok(status == LTTNG_ACTION_STATUS_INVALID,
-                       "Set session name (NULL,object) expect invalid");
-
-       /* Set the session name */
-       status = lttng_action_start_session_set_session_name(
-                       start_session_action, session_name);
-       ok(status == LTTNG_ACTION_STATUS_OK, "Set session name");
-
-       status = lttng_action_start_session_get_session_name(
-                       start_session_action, &get_session_name);
-       ok(status == LTTNG_ACTION_STATUS_OK &&
-                                       !strcmp(session_name, get_session_name),
-                       "Get session name, expected `%s` got `%s`",
-                       session_name, get_session_name);
-
-       /* Validate the default policy for a start_session action. */
-       {
-               const struct lttng_rate_policy *cur_policy = NULL;
-               status = lttng_action_start_session_get_rate_policy(
-                               start_session_action, &cur_policy);
-               ok(status == LTTNG_ACTION_STATUS_OK &&
-                                               lttng_rate_policy_is_equal(
-                                                               default_policy,
-                                                               cur_policy),
-                               "Default policy is every n=1");
-       }
-
-       /* Set a custom policy. */
-       status = lttng_action_start_session_set_rate_policy(
-                       start_session_action, policy);
-       ok(status == LTTNG_ACTION_STATUS_OK, "Set rate policy");
-
-       /* Validate the custom policy for a start_session action. */
-       {
-               const struct lttng_rate_policy *cur_policy = NULL;
-               status = lttng_action_start_session_get_rate_policy(
-                               start_session_action, &cur_policy);
-               ok(status == LTTNG_ACTION_STATUS_OK &&
-                                               lttng_rate_policy_is_equal(
-                                                               policy,
-                                                               cur_policy),
-                               "start_session action policy get");
-       }
-
-       /* Ser/des tests. */
-       ret = lttng_action_serialize(start_session_action, &payload);
-       ok(ret == 0, "Action start_session serialized");
-
-       {
-               struct lttng_payload_view view =
-                               lttng_payload_view_from_payload(
-                                               &payload, 0, -1);
-               (void) lttng_action_create_from_payload(
-                               &view, &start_session_action_from_buffer);
-       }
-       ok(start_session_action_from_buffer,
-                       "start_session action created from payload is non-null");
-
-       ok(lttng_action_is_equal(start_session_action,
-                          start_session_action_from_buffer),
-                       "Serialized and de-serialized start_session action are equal");
-
-       lttng_rate_policy_destroy(default_policy);
-       lttng_rate_policy_destroy(policy);
-       lttng_action_destroy(start_session_action);
-       lttng_action_destroy(start_session_action_from_buffer);
-       lttng_payload_reset(&payload);
-}
-
-static void test_action_stop_session(void)
-{
-       int ret;
-       enum lttng_action_status status;
-       struct lttng_action *stop_session_action = NULL,
-                           *stop_session_action_from_buffer = NULL;
-       struct lttng_rate_policy *policy = NULL, *default_policy;
-       struct lttng_payload payload;
-       const char *session_name = "my_session_name";
-       const char *get_session_name;
-
-       lttng_payload_init(&payload);
-
-       /* To set. */
-       policy = lttng_rate_policy_every_n_create(100);
-       /* For comparison. */
-       default_policy = lttng_rate_policy_every_n_create(1);
-
-       LTTNG_ASSERT(policy && default_policy);
-
-       stop_session_action = lttng_action_stop_session_create();
-       ok(stop_session_action, "Create stop_session action");
-       ok(lttng_action_get_type(stop_session_action) ==
-                                       LTTNG_ACTION_TYPE_STOP_SESSION,
-                       "Action has type LTTNG_ACTION_TYPE_STOP_SESSION");
-
-       /* Session name setter. */
-       status = lttng_action_stop_session_set_session_name(NULL, NULL);
-       ok(status == LTTNG_ACTION_STATUS_INVALID,
-                       "Set session name (NULL,NULL) expect invalid");
-       status = lttng_action_stop_session_set_session_name(
-                       stop_session_action, NULL);
-       ok(status == LTTNG_ACTION_STATUS_INVALID,
-                       "Set session name (object,NULL) expect invalid");
-       status = lttng_action_stop_session_set_session_name(NULL, session_name);
-       ok(status == LTTNG_ACTION_STATUS_INVALID,
-                       "Set session name (NULL,object) expect invalid");
-
-       /* Set the session name */
-       status = lttng_action_stop_session_set_session_name(
-                       stop_session_action, session_name);
-       ok(status == LTTNG_ACTION_STATUS_OK, "Set session name");
-
-       status = lttng_action_stop_session_get_session_name(
-                       stop_session_action, &get_session_name);
-       ok(status == LTTNG_ACTION_STATUS_OK &&
-                                       !strcmp(session_name, get_session_name),
-                       "Get session name, expected `%s` got `%s`",
-                       session_name, get_session_name);
-
-       /* Validate the default policy for a stop_session action. */
-       {
-               const struct lttng_rate_policy *cur_policy = NULL;
-               status = lttng_action_stop_session_get_rate_policy(
-                               stop_session_action, &cur_policy);
-               ok(status == LTTNG_ACTION_STATUS_OK &&
-                                               lttng_rate_policy_is_equal(
-                                                               default_policy,
-                                                               cur_policy),
-                               "Default policy is every n=1");
-       }
-
-       /* Set a custom policy. */
-       status = lttng_action_stop_session_set_rate_policy(
-                       stop_session_action, policy);
-       ok(status == LTTNG_ACTION_STATUS_OK, "Set rate policy");
-
-       /* Validate the custom policy for a stop_session action. */
-       {
-               const struct lttng_rate_policy *cur_policy = NULL;
-               status = lttng_action_stop_session_get_rate_policy(
-                               stop_session_action, &cur_policy);
-               ok(status == LTTNG_ACTION_STATUS_OK &&
-                                               lttng_rate_policy_is_equal(
-                                                               policy,
-                                                               cur_policy),
-                               "stop_session action policy get");
-       }
-
-       /* Ser/des tests. */
-       ret = lttng_action_serialize(stop_session_action, &payload);
-       ok(ret == 0, "Action stop_session serialized");
-
-       {
-               struct lttng_payload_view view =
-                               lttng_payload_view_from_payload(
-                                               &payload, 0, -1);
-               (void) lttng_action_create_from_payload(
-                               &view, &stop_session_action_from_buffer);
-       }
-       ok(stop_session_action_from_buffer,
-                       "stop_session action created from payload is non-null");
-
-       ok(lttng_action_is_equal(stop_session_action,
-                          stop_session_action_from_buffer),
-                       "Serialized and de-serialized stop_session action are equal");
-
-       lttng_rate_policy_destroy(default_policy);
-       lttng_rate_policy_destroy(policy);
-       lttng_action_destroy(stop_session_action);
-       lttng_action_destroy(stop_session_action_from_buffer);
-       lttng_payload_reset(&payload);
-}
-
-static void test_action_snapshot_session(void)
-{
-       int ret;
-       enum lttng_action_status status;
-       struct lttng_action *snapshot_session_action = NULL,
-                           *snapshot_session_action_from_buffer = NULL;
-       struct lttng_rate_policy *policy = NULL, *default_policy;
-       struct lttng_payload payload;
-       const char *session_name = "my_session_name";
-       const char *get_session_name;
-
-       lttng_payload_init(&payload);
-
-       /* To set. */
-       policy = lttng_rate_policy_every_n_create(100);
-       /* For comparison. */
-       default_policy = lttng_rate_policy_every_n_create(1);
-
-       LTTNG_ASSERT(policy && default_policy);
-
-       snapshot_session_action = lttng_action_snapshot_session_create();
-       ok(snapshot_session_action, "Create snapshot_session action");
-       ok(lttng_action_get_type(snapshot_session_action) ==
-                                       LTTNG_ACTION_TYPE_SNAPSHOT_SESSION,
-                       "Action has type LTTNG_ACTION_TYPE_SNAPSHOT_SESSION");
-
-       /* Session name setter. */
-       status = lttng_action_snapshot_session_set_session_name(NULL, NULL);
-       ok(status == LTTNG_ACTION_STATUS_INVALID,
-                       "Set session name (NULL,NULL) expect invalid");
-       status = lttng_action_snapshot_session_set_session_name(
-                       snapshot_session_action, NULL);
-       ok(status == LTTNG_ACTION_STATUS_INVALID,
-                       "Set session name (object,NULL) expect invalid");
-       status = lttng_action_snapshot_session_set_session_name(
-                       NULL, session_name);
-       ok(status == LTTNG_ACTION_STATUS_INVALID,
-                       "Set session name (NULL,object) expect invalid");
-
-       /* Set the session name */
-       status = lttng_action_snapshot_session_set_session_name(
-                       snapshot_session_action, session_name);
-       ok(status == LTTNG_ACTION_STATUS_OK, "Set session name");
-
-       status = lttng_action_snapshot_session_get_session_name(
-                       snapshot_session_action, &get_session_name);
-       ok(status == LTTNG_ACTION_STATUS_OK &&
-                                       !strcmp(session_name, get_session_name),
-                       "Get session name, expected `%s` got `%s`",
-                       session_name, get_session_name);
-
-       /* Validate the default policy for a snapshot_session action. */
-       {
-               const struct lttng_rate_policy *cur_policy = NULL;
-               status = lttng_action_snapshot_session_get_rate_policy(
-                               snapshot_session_action, &cur_policy);
-               ok(status == LTTNG_ACTION_STATUS_OK &&
-                                               lttng_rate_policy_is_equal(
-                                                               default_policy,
-                                                               cur_policy),
-                               "Default policy is every n=1");
-       }
-
-       /* Set a custom policy. */
-       status = lttng_action_snapshot_session_set_rate_policy(
-                       snapshot_session_action, policy);
-       ok(status == LTTNG_ACTION_STATUS_OK, "Set rate policy");
-
-       /* Validate the custom policy for a snapshot_session action. */
-       {
-               const struct lttng_rate_policy *cur_policy = NULL;
-               status = lttng_action_snapshot_session_get_rate_policy(
-                               snapshot_session_action, &cur_policy);
-               ok(status == LTTNG_ACTION_STATUS_OK &&
-                                               lttng_rate_policy_is_equal(
-                                                               policy,
-                                                               cur_policy),
-                               "snapshot_session action policy get");
-       }
-
-       /* Ser/des tests. */
-       ret = lttng_action_serialize(snapshot_session_action, &payload);
-       ok(ret == 0, "Action snapshot_session serialized");
-
-       {
-               struct lttng_payload_view view =
-                               lttng_payload_view_from_payload(
-                                               &payload, 0, -1);
-               (void) lttng_action_create_from_payload(
-                               &view, &snapshot_session_action_from_buffer);
-       }
-       ok(snapshot_session_action_from_buffer,
-                       "snapshot_session action created from payload is non-null");
-
-       ok(lttng_action_is_equal(snapshot_session_action,
-                          snapshot_session_action_from_buffer),
-                       "Serialized and de-serialized snapshot_session action are equal");
-
-       lttng_rate_policy_destroy(default_policy);
-       lttng_rate_policy_destroy(policy);
-       lttng_action_destroy(snapshot_session_action);
-       lttng_action_destroy(snapshot_session_action_from_buffer);
-       lttng_payload_reset(&payload);
-}
-
-int main(int argc, const char *argv[])
-{
-       plan_tests(NUM_TESTS);
-       test_action_notify();
-       test_action_rotate_session();
-       test_action_start_session();
-       test_action_stop_session();
-       test_action_snapshot_session();
-       return exit_status();
-}
diff --git a/tests/unit/test_action.cpp b/tests/unit/test_action.cpp
new file mode 100644 (file)
index 0000000..ad323e9
--- /dev/null
@@ -0,0 +1,540 @@
+/*
+ * test_action.c
+ *
+ * Unit tests for the notification API.
+ *
+ * Copyright (C) 2017 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ */
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <tap/tap.h>
+
+#include <common/payload-view.h>
+#include <common/payload.h>
+#include <lttng/action/action-internal.h>
+#include <lttng/action/action.h>
+#include <lttng/action/notify.h>
+#include <lttng/action/rate-policy-internal.h>
+#include <lttng/action/rate-policy.h>
+#include <lttng/action/rotate-session.h>
+#include <lttng/action/snapshot-session.h>
+#include <lttng/action/start-session.h>
+#include <lttng/action/stop-session.h>
+
+/* For error.h */
+int lttng_opt_quiet = 1;
+int lttng_opt_verbose;
+int lttng_opt_mi;
+
+#define NUM_TESTS 60
+
+static void test_action_notify(void)
+{
+       int ret;
+       enum lttng_action_status status;
+       struct lttng_action *notify_action = NULL,
+                           *notify_action_from_buffer = NULL;
+       struct lttng_rate_policy *policy = NULL, *default_policy;
+       struct lttng_payload payload;
+
+       lttng_payload_init(&payload);
+
+       /* To set. */
+       policy = lttng_rate_policy_every_n_create(100);
+       /* For comparison. */
+       default_policy = lttng_rate_policy_every_n_create(1);
+
+       LTTNG_ASSERT(policy && default_policy);
+
+       notify_action = lttng_action_notify_create();
+       ok(notify_action, "Create notify action");
+       ok(lttng_action_get_type(notify_action) == LTTNG_ACTION_TYPE_NOTIFY,
+                       "Action has type LTTNG_ACTION_TYPE_NOTIFY");
+
+       /* Validate the default policy for a notify action. */
+       {
+               const struct lttng_rate_policy *cur_policy = NULL;
+               status = lttng_action_notify_get_rate_policy(
+                               notify_action, &cur_policy);
+               ok(status == LTTNG_ACTION_STATUS_OK &&
+                                               lttng_rate_policy_is_equal(
+                                                               default_policy,
+                                                               cur_policy),
+                               "Default policy is every n=1");
+       }
+
+       /* Set a custom policy. */
+       status = lttng_action_notify_set_rate_policy(notify_action, policy);
+       ok(status == LTTNG_ACTION_STATUS_OK, "Set rate policy");
+
+       /* Validate the custom policy for a notify action. */
+       {
+               const struct lttng_rate_policy *cur_policy = NULL;
+               status = lttng_action_notify_get_rate_policy(
+                               notify_action, &cur_policy);
+               ok(status == LTTNG_ACTION_STATUS_OK &&
+                                               lttng_rate_policy_is_equal(
+                                                               policy,
+                                                               cur_policy),
+                               "Notify action policy get");
+       }
+
+       ret = lttng_action_serialize(notify_action, &payload);
+       ok(ret == 0, "Action notify serialized");
+
+       {
+               struct lttng_payload_view view =
+                               lttng_payload_view_from_payload(
+                                               &payload, 0, -1);
+               (void) lttng_action_create_from_payload(
+                               &view, &notify_action_from_buffer);
+       }
+       ok(notify_action_from_buffer,
+                       "Notify action created from payload is non-null");
+
+       ok(lttng_action_is_equal(notify_action, notify_action_from_buffer),
+                       "Serialized and de-serialized notify action are equal");
+
+       lttng_rate_policy_destroy(default_policy);
+       lttng_rate_policy_destroy(policy);
+       lttng_action_destroy(notify_action);
+       lttng_action_destroy(notify_action_from_buffer);
+       lttng_payload_reset(&payload);
+}
+
+static void test_action_rotate_session(void)
+{
+       int ret;
+       enum lttng_action_status status;
+       struct lttng_action *rotate_session_action = NULL,
+                           *rotate_session_action_from_buffer = NULL;
+       struct lttng_rate_policy *policy = NULL, *default_policy;
+       struct lttng_payload payload;
+       const char *session_name = "my_session_name";
+       const char *get_session_name;
+
+       lttng_payload_init(&payload);
+
+       /* To set. */
+       policy = lttng_rate_policy_every_n_create(100);
+       /* For comparison. */
+       default_policy = lttng_rate_policy_every_n_create(1);
+
+       LTTNG_ASSERT(policy && default_policy);
+
+       rotate_session_action = lttng_action_rotate_session_create();
+       ok(rotate_session_action, "Create rotate_session action");
+       ok(lttng_action_get_type(rotate_session_action) ==
+                                       LTTNG_ACTION_TYPE_ROTATE_SESSION,
+                       "Action has type LTTNG_ACTION_TYPE_ROTATE_SESSION");
+
+       /* Session name setter. */
+       status = lttng_action_rotate_session_set_session_name(NULL, NULL);
+       ok(status == LTTNG_ACTION_STATUS_INVALID,
+                       "Set session name (NULL,NULL) expect invalid");
+       status = lttng_action_rotate_session_set_session_name(
+                       rotate_session_action, NULL);
+       ok(status == LTTNG_ACTION_STATUS_INVALID,
+                       "Set session name (object,NULL) expect invalid");
+       status = lttng_action_rotate_session_set_session_name(
+                       NULL, session_name);
+       ok(status == LTTNG_ACTION_STATUS_INVALID,
+                       "Set session name (NULL,object) expect invalid");
+
+       /* Set the session name */
+       status = lttng_action_rotate_session_set_session_name(
+                       rotate_session_action, session_name);
+       ok(status == LTTNG_ACTION_STATUS_OK, "Set session name");
+
+       status = lttng_action_rotate_session_get_session_name(
+                       rotate_session_action, &get_session_name);
+       ok(status == LTTNG_ACTION_STATUS_OK &&
+                                       !strcmp(session_name, get_session_name),
+                       "Get session name, expected `%s` got `%s`",
+                       session_name, get_session_name);
+
+       /* Validate the default policy for a rotate_session action. */
+       {
+               const struct lttng_rate_policy *cur_policy = NULL;
+               status = lttng_action_rotate_session_get_rate_policy(
+                               rotate_session_action, &cur_policy);
+               ok(status == LTTNG_ACTION_STATUS_OK &&
+                                               lttng_rate_policy_is_equal(
+                                                               default_policy,
+                                                               cur_policy),
+                               "Default policy is every n=1");
+       }
+
+       /* Set a custom policy. */
+       status = lttng_action_rotate_session_set_rate_policy(
+                       rotate_session_action, policy);
+       ok(status == LTTNG_ACTION_STATUS_OK, "Set rate policy");
+
+       /* Validate the custom policy for a rotate_session action. */
+       {
+               const struct lttng_rate_policy *cur_policy = NULL;
+               status = lttng_action_rotate_session_get_rate_policy(
+                               rotate_session_action, &cur_policy);
+               ok(status == LTTNG_ACTION_STATUS_OK &&
+                                               lttng_rate_policy_is_equal(
+                                                               policy,
+                                                               cur_policy),
+                               "rotate_session action policy get");
+       }
+
+       /* Ser/des tests. */
+       ret = lttng_action_serialize(rotate_session_action, &payload);
+       ok(ret == 0, "Action rotate_session serialized");
+
+       {
+               struct lttng_payload_view view =
+                               lttng_payload_view_from_payload(
+                                               &payload, 0, -1);
+               (void) lttng_action_create_from_payload(
+                               &view, &rotate_session_action_from_buffer);
+       }
+       ok(rotate_session_action_from_buffer,
+                       "rotate_session action created from payload is non-null");
+
+       ok(lttng_action_is_equal(rotate_session_action,
+                          rotate_session_action_from_buffer),
+                       "Serialized and de-serialized rotate_session action are equal");
+
+       lttng_rate_policy_destroy(default_policy);
+       lttng_rate_policy_destroy(policy);
+       lttng_action_destroy(rotate_session_action);
+       lttng_action_destroy(rotate_session_action_from_buffer);
+       lttng_payload_reset(&payload);
+}
+
+static void test_action_start_session(void)
+{
+       int ret;
+       enum lttng_action_status status;
+       struct lttng_action *start_session_action = NULL,
+                           *start_session_action_from_buffer = NULL;
+       struct lttng_rate_policy *policy = NULL, *default_policy;
+       struct lttng_payload payload;
+       const char *session_name = "my_session_name";
+       const char *get_session_name;
+
+       lttng_payload_init(&payload);
+
+       /* To set. */
+       policy = lttng_rate_policy_every_n_create(100);
+       /* For comparison. */
+       default_policy = lttng_rate_policy_every_n_create(1);
+
+       LTTNG_ASSERT(policy && default_policy);
+
+       start_session_action = lttng_action_start_session_create();
+       ok(start_session_action, "Create start_session action");
+       ok(lttng_action_get_type(start_session_action) ==
+                                       LTTNG_ACTION_TYPE_START_SESSION,
+                       "Action has type LTTNG_ACTION_TYPE_START_SESSION");
+
+       /* Session name setter. */
+       status = lttng_action_start_session_set_session_name(NULL, NULL);
+       ok(status == LTTNG_ACTION_STATUS_INVALID,
+                       "Set session name (NULL,NULL) expect invalid");
+       status = lttng_action_start_session_set_session_name(
+                       start_session_action, NULL);
+       ok(status == LTTNG_ACTION_STATUS_INVALID,
+                       "Set session name (object,NULL) expect invalid");
+       status = lttng_action_start_session_set_session_name(
+                       NULL, session_name);
+       ok(status == LTTNG_ACTION_STATUS_INVALID,
+                       "Set session name (NULL,object) expect invalid");
+
+       /* Set the session name */
+       status = lttng_action_start_session_set_session_name(
+                       start_session_action, session_name);
+       ok(status == LTTNG_ACTION_STATUS_OK, "Set session name");
+
+       status = lttng_action_start_session_get_session_name(
+                       start_session_action, &get_session_name);
+       ok(status == LTTNG_ACTION_STATUS_OK &&
+                                       !strcmp(session_name, get_session_name),
+                       "Get session name, expected `%s` got `%s`",
+                       session_name, get_session_name);
+
+       /* Validate the default policy for a start_session action. */
+       {
+               const struct lttng_rate_policy *cur_policy = NULL;
+               status = lttng_action_start_session_get_rate_policy(
+                               start_session_action, &cur_policy);
+               ok(status == LTTNG_ACTION_STATUS_OK &&
+                                               lttng_rate_policy_is_equal(
+                                                               default_policy,
+                                                               cur_policy),
+                               "Default policy is every n=1");
+       }
+
+       /* Set a custom policy. */
+       status = lttng_action_start_session_set_rate_policy(
+                       start_session_action, policy);
+       ok(status == LTTNG_ACTION_STATUS_OK, "Set rate policy");
+
+       /* Validate the custom policy for a start_session action. */
+       {
+               const struct lttng_rate_policy *cur_policy = NULL;
+               status = lttng_action_start_session_get_rate_policy(
+                               start_session_action, &cur_policy);
+               ok(status == LTTNG_ACTION_STATUS_OK &&
+                                               lttng_rate_policy_is_equal(
+                                                               policy,
+                                                               cur_policy),
+                               "start_session action policy get");
+       }
+
+       /* Ser/des tests. */
+       ret = lttng_action_serialize(start_session_action, &payload);
+       ok(ret == 0, "Action start_session serialized");
+
+       {
+               struct lttng_payload_view view =
+                               lttng_payload_view_from_payload(
+                                               &payload, 0, -1);
+               (void) lttng_action_create_from_payload(
+                               &view, &start_session_action_from_buffer);
+       }
+       ok(start_session_action_from_buffer,
+                       "start_session action created from payload is non-null");
+
+       ok(lttng_action_is_equal(start_session_action,
+                          start_session_action_from_buffer),
+                       "Serialized and de-serialized start_session action are equal");
+
+       lttng_rate_policy_destroy(default_policy);
+       lttng_rate_policy_destroy(policy);
+       lttng_action_destroy(start_session_action);
+       lttng_action_destroy(start_session_action_from_buffer);
+       lttng_payload_reset(&payload);
+}
+
+static void test_action_stop_session(void)
+{
+       int ret;
+       enum lttng_action_status status;
+       struct lttng_action *stop_session_action = NULL,
+                           *stop_session_action_from_buffer = NULL;
+       struct lttng_rate_policy *policy = NULL, *default_policy;
+       struct lttng_payload payload;
+       const char *session_name = "my_session_name";
+       const char *get_session_name;
+
+       lttng_payload_init(&payload);
+
+       /* To set. */
+       policy = lttng_rate_policy_every_n_create(100);
+       /* For comparison. */
+       default_policy = lttng_rate_policy_every_n_create(1);
+
+       LTTNG_ASSERT(policy && default_policy);
+
+       stop_session_action = lttng_action_stop_session_create();
+       ok(stop_session_action, "Create stop_session action");
+       ok(lttng_action_get_type(stop_session_action) ==
+                                       LTTNG_ACTION_TYPE_STOP_SESSION,
+                       "Action has type LTTNG_ACTION_TYPE_STOP_SESSION");
+
+       /* Session name setter. */
+       status = lttng_action_stop_session_set_session_name(NULL, NULL);
+       ok(status == LTTNG_ACTION_STATUS_INVALID,
+                       "Set session name (NULL,NULL) expect invalid");
+       status = lttng_action_stop_session_set_session_name(
+                       stop_session_action, NULL);
+       ok(status == LTTNG_ACTION_STATUS_INVALID,
+                       "Set session name (object,NULL) expect invalid");
+       status = lttng_action_stop_session_set_session_name(NULL, session_name);
+       ok(status == LTTNG_ACTION_STATUS_INVALID,
+                       "Set session name (NULL,object) expect invalid");
+
+       /* Set the session name */
+       status = lttng_action_stop_session_set_session_name(
+                       stop_session_action, session_name);
+       ok(status == LTTNG_ACTION_STATUS_OK, "Set session name");
+
+       status = lttng_action_stop_session_get_session_name(
+                       stop_session_action, &get_session_name);
+       ok(status == LTTNG_ACTION_STATUS_OK &&
+                                       !strcmp(session_name, get_session_name),
+                       "Get session name, expected `%s` got `%s`",
+                       session_name, get_session_name);
+
+       /* Validate the default policy for a stop_session action. */
+       {
+               const struct lttng_rate_policy *cur_policy = NULL;
+               status = lttng_action_stop_session_get_rate_policy(
+                               stop_session_action, &cur_policy);
+               ok(status == LTTNG_ACTION_STATUS_OK &&
+                                               lttng_rate_policy_is_equal(
+                                                               default_policy,
+                                                               cur_policy),
+                               "Default policy is every n=1");
+       }
+
+       /* Set a custom policy. */
+       status = lttng_action_stop_session_set_rate_policy(
+                       stop_session_action, policy);
+       ok(status == LTTNG_ACTION_STATUS_OK, "Set rate policy");
+
+       /* Validate the custom policy for a stop_session action. */
+       {
+               const struct lttng_rate_policy *cur_policy = NULL;
+               status = lttng_action_stop_session_get_rate_policy(
+                               stop_session_action, &cur_policy);
+               ok(status == LTTNG_ACTION_STATUS_OK &&
+                                               lttng_rate_policy_is_equal(
+                                                               policy,
+                                                               cur_policy),
+                               "stop_session action policy get");
+       }
+
+       /* Ser/des tests. */
+       ret = lttng_action_serialize(stop_session_action, &payload);
+       ok(ret == 0, "Action stop_session serialized");
+
+       {
+               struct lttng_payload_view view =
+                               lttng_payload_view_from_payload(
+                                               &payload, 0, -1);
+               (void) lttng_action_create_from_payload(
+                               &view, &stop_session_action_from_buffer);
+       }
+       ok(stop_session_action_from_buffer,
+                       "stop_session action created from payload is non-null");
+
+       ok(lttng_action_is_equal(stop_session_action,
+                          stop_session_action_from_buffer),
+                       "Serialized and de-serialized stop_session action are equal");
+
+       lttng_rate_policy_destroy(default_policy);
+       lttng_rate_policy_destroy(policy);
+       lttng_action_destroy(stop_session_action);
+       lttng_action_destroy(stop_session_action_from_buffer);
+       lttng_payload_reset(&payload);
+}
+
+static void test_action_snapshot_session(void)
+{
+       int ret;
+       enum lttng_action_status status;
+       struct lttng_action *snapshot_session_action = NULL,
+                           *snapshot_session_action_from_buffer = NULL;
+       struct lttng_rate_policy *policy = NULL, *default_policy;
+       struct lttng_payload payload;
+       const char *session_name = "my_session_name";
+       const char *get_session_name;
+
+       lttng_payload_init(&payload);
+
+       /* To set. */
+       policy = lttng_rate_policy_every_n_create(100);
+       /* For comparison. */
+       default_policy = lttng_rate_policy_every_n_create(1);
+
+       LTTNG_ASSERT(policy && default_policy);
+
+       snapshot_session_action = lttng_action_snapshot_session_create();
+       ok(snapshot_session_action, "Create snapshot_session action");
+       ok(lttng_action_get_type(snapshot_session_action) ==
+                                       LTTNG_ACTION_TYPE_SNAPSHOT_SESSION,
+                       "Action has type LTTNG_ACTION_TYPE_SNAPSHOT_SESSION");
+
+       /* Session name setter. */
+       status = lttng_action_snapshot_session_set_session_name(NULL, NULL);
+       ok(status == LTTNG_ACTION_STATUS_INVALID,
+                       "Set session name (NULL,NULL) expect invalid");
+       status = lttng_action_snapshot_session_set_session_name(
+                       snapshot_session_action, NULL);
+       ok(status == LTTNG_ACTION_STATUS_INVALID,
+                       "Set session name (object,NULL) expect invalid");
+       status = lttng_action_snapshot_session_set_session_name(
+                       NULL, session_name);
+       ok(status == LTTNG_ACTION_STATUS_INVALID,
+                       "Set session name (NULL,object) expect invalid");
+
+       /* Set the session name */
+       status = lttng_action_snapshot_session_set_session_name(
+                       snapshot_session_action, session_name);
+       ok(status == LTTNG_ACTION_STATUS_OK, "Set session name");
+
+       status = lttng_action_snapshot_session_get_session_name(
+                       snapshot_session_action, &get_session_name);
+       ok(status == LTTNG_ACTION_STATUS_OK &&
+                                       !strcmp(session_name, get_session_name),
+                       "Get session name, expected `%s` got `%s`",
+                       session_name, get_session_name);
+
+       /* Validate the default policy for a snapshot_session action. */
+       {
+               const struct lttng_rate_policy *cur_policy = NULL;
+               status = lttng_action_snapshot_session_get_rate_policy(
+                               snapshot_session_action, &cur_policy);
+               ok(status == LTTNG_ACTION_STATUS_OK &&
+                                               lttng_rate_policy_is_equal(
+                                                               default_policy,
+                                                               cur_policy),
+                               "Default policy is every n=1");
+       }
+
+       /* Set a custom policy. */
+       status = lttng_action_snapshot_session_set_rate_policy(
+                       snapshot_session_action, policy);
+       ok(status == LTTNG_ACTION_STATUS_OK, "Set rate policy");
+
+       /* Validate the custom policy for a snapshot_session action. */
+       {
+               const struct lttng_rate_policy *cur_policy = NULL;
+               status = lttng_action_snapshot_session_get_rate_policy(
+                               snapshot_session_action, &cur_policy);
+               ok(status == LTTNG_ACTION_STATUS_OK &&
+                                               lttng_rate_policy_is_equal(
+                                                               policy,
+                                                               cur_policy),
+                               "snapshot_session action policy get");
+       }
+
+       /* Ser/des tests. */
+       ret = lttng_action_serialize(snapshot_session_action, &payload);
+       ok(ret == 0, "Action snapshot_session serialized");
+
+       {
+               struct lttng_payload_view view =
+                               lttng_payload_view_from_payload(
+                                               &payload, 0, -1);
+               (void) lttng_action_create_from_payload(
+                               &view, &snapshot_session_action_from_buffer);
+       }
+       ok(snapshot_session_action_from_buffer,
+                       "snapshot_session action created from payload is non-null");
+
+       ok(lttng_action_is_equal(snapshot_session_action,
+                          snapshot_session_action_from_buffer),
+                       "Serialized and de-serialized snapshot_session action are equal");
+
+       lttng_rate_policy_destroy(default_policy);
+       lttng_rate_policy_destroy(policy);
+       lttng_action_destroy(snapshot_session_action);
+       lttng_action_destroy(snapshot_session_action_from_buffer);
+       lttng_payload_reset(&payload);
+}
+
+int main(int argc, const char *argv[])
+{
+       plan_tests(NUM_TESTS);
+       test_action_notify();
+       test_action_rotate_session();
+       test_action_start_session();
+       test_action_stop_session();
+       test_action_snapshot_session();
+       return exit_status();
+}
diff --git a/tests/unit/test_buffer_view.c b/tests/unit/test_buffer_view.c
deleted file mode 100644 (file)
index a129d4a..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2020 EfficiOS, inc.
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-
-#include <common/buffer-view.h>
-#include <tap/tap.h>
-
-static const int TEST_COUNT = 5;
-
-/* For error.h */
-int lttng_opt_quiet = 1;
-int lttng_opt_verbose;
-int lttng_opt_mi;
-
-static void test_contains_string(void)
-{
-       const char buf[] = {'A', 'l', 'l', 'o', '\0'};
-       struct lttng_buffer_view view = lttng_buffer_view_init(buf, 0, 5);
-       struct lttng_buffer_view view_minus_one =
-                       lttng_buffer_view_init(buf, 0, 4);
-
-       ok1(!lttng_buffer_view_contains_string(&view, buf, 4));
-       ok1(lttng_buffer_view_contains_string(&view, buf, 5));
-       ok1(!lttng_buffer_view_contains_string(&view, buf, 6));
-
-       ok1(!lttng_buffer_view_contains_string(&view_minus_one, buf, 4));
-       ok1(!lttng_buffer_view_contains_string(&view_minus_one, buf, 5));
-}
-
-int main(void)
-{
-       plan_tests(TEST_COUNT);
-
-       test_contains_string();
-
-       return exit_status();
-}
diff --git a/tests/unit/test_buffer_view.cpp b/tests/unit/test_buffer_view.cpp
new file mode 100644 (file)
index 0000000..a129d4a
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2020 EfficiOS, inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+
+#include <common/buffer-view.h>
+#include <tap/tap.h>
+
+static const int TEST_COUNT = 5;
+
+/* For error.h */
+int lttng_opt_quiet = 1;
+int lttng_opt_verbose;
+int lttng_opt_mi;
+
+static void test_contains_string(void)
+{
+       const char buf[] = {'A', 'l', 'l', 'o', '\0'};
+       struct lttng_buffer_view view = lttng_buffer_view_init(buf, 0, 5);
+       struct lttng_buffer_view view_minus_one =
+                       lttng_buffer_view_init(buf, 0, 4);
+
+       ok1(!lttng_buffer_view_contains_string(&view, buf, 4));
+       ok1(lttng_buffer_view_contains_string(&view, buf, 5));
+       ok1(!lttng_buffer_view_contains_string(&view, buf, 6));
+
+       ok1(!lttng_buffer_view_contains_string(&view_minus_one, buf, 4));
+       ok1(!lttng_buffer_view_contains_string(&view_minus_one, buf, 5));
+}
+
+int main(void)
+{
+       plan_tests(TEST_COUNT);
+
+       test_contains_string();
+
+       return exit_status();
+}
diff --git a/tests/unit/test_condition.c b/tests/unit/test_condition.c
deleted file mode 100644 (file)
index 1ed14fa..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * test_condition.c
- *
- * Unit tests for the condition API.
- *
- * Copyright (C) 2019 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-#include <inttypes.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <tap/tap.h>
-
-#include <lttng/event.h>
-#include <lttng/event-rule/user-tracepoint.h>
-#include <lttng/condition/condition-internal.h>
-#include <lttng/condition/event-rule-matches.h>
-#include <lttng/condition/event-rule-matches-internal.h>
-#include <lttng/domain.h>
-#include <lttng/log-level-rule.h>
-#include <common/dynamic-buffer.h>
-#include <common/buffer-view.h>
-
-/* For error.h */
-int lttng_opt_quiet = 1;
-int lttng_opt_verbose;
-int lttng_opt_mi;
-
-#define NUM_TESTS 13
-
-static
-void test_condition_event_rule(void)
-{
-       int ret, i;
-       struct lttng_event_rule *tracepoint = NULL;
-       const struct lttng_event_rule *tracepoint_tmp = NULL;
-       enum lttng_event_rule_status status;
-       struct lttng_condition *condition = NULL;
-       struct lttng_condition *condition_from_buffer = NULL;
-       enum lttng_condition_status condition_status;
-       const char *pattern="my_event_*";
-       const char *filter="msg_id == 23 && size >= 2048";
-       const char *exclusions[] = { "my_event_test1", "my_event_test2", "my_event_test3" };
-       struct lttng_log_level_rule *log_level_rule_at_least_as_severe = NULL;
-       struct lttng_payload buffer;
-
-       lttng_payload_init(&buffer);
-
-       /* Create log level rule. */
-       log_level_rule_at_least_as_severe =
-                       lttng_log_level_rule_at_least_as_severe_as_create(
-                                       LTTNG_LOGLEVEL_WARNING);
-       LTTNG_ASSERT(log_level_rule_at_least_as_severe);
-
-       tracepoint = lttng_event_rule_user_tracepoint_create();
-       ok(tracepoint, "user tracepoint");
-
-       status = lttng_event_rule_user_tracepoint_set_name_pattern(tracepoint, pattern);
-       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "Setting pattern");
-
-       status = lttng_event_rule_user_tracepoint_set_filter(tracepoint, filter);
-       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "Setting filter");
-
-       status = lttng_event_rule_user_tracepoint_set_log_level_rule(
-                       tracepoint, log_level_rule_at_least_as_severe);
-       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "Setting log level range");
-
-       for (i = 0; i < 3; i++) {
-               status = lttng_event_rule_user_tracepoint_add_name_pattern_exclusion(
-                               tracepoint, exclusions[i]);
-               ok(status == LTTNG_EVENT_RULE_STATUS_OK,
-                               "Setting exclusion pattern");
-       }
-
-       condition = lttng_condition_event_rule_matches_create(tracepoint);
-       ok(condition, "Created condition");
-
-       condition_status = lttng_condition_event_rule_matches_get_rule(
-                       condition, &tracepoint_tmp);
-       ok(condition_status == LTTNG_CONDITION_STATUS_OK,
-                       "Getting event rule from event rule condition");
-       ok(tracepoint == tracepoint_tmp, "lttng_condition_event_rule_get_rule provides a reference to the original rule");
-
-       ret = lttng_condition_serialize(condition, &buffer);
-       ok(ret == 0, "Condition serialized");
-
-       {
-               struct lttng_payload_view view =
-                               lttng_payload_view_from_payload(&buffer, 0, -1);
-
-               (void) lttng_condition_create_from_payload(
-                               &view, &condition_from_buffer);
-       }
-
-       ok(condition_from_buffer, "Condition created from payload is non-null");
-
-       ok(lttng_condition_is_equal(condition, condition_from_buffer),
-                       "Serialized and de-serialized conditions are equal");
-
-       lttng_payload_reset(&buffer);
-       lttng_event_rule_destroy(tracepoint);
-       lttng_condition_destroy(condition);
-       lttng_condition_destroy(condition_from_buffer);
-       lttng_log_level_rule_destroy(log_level_rule_at_least_as_severe);
-}
-
-int main(int argc, const char *argv[])
-{
-       plan_tests(NUM_TESTS);
-       test_condition_event_rule();
-       return exit_status();
-}
diff --git a/tests/unit/test_condition.cpp b/tests/unit/test_condition.cpp
new file mode 100644 (file)
index 0000000..1ed14fa
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * test_condition.c
+ *
+ * Unit tests for the condition API.
+ *
+ * Copyright (C) 2019 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <tap/tap.h>
+
+#include <lttng/event.h>
+#include <lttng/event-rule/user-tracepoint.h>
+#include <lttng/condition/condition-internal.h>
+#include <lttng/condition/event-rule-matches.h>
+#include <lttng/condition/event-rule-matches-internal.h>
+#include <lttng/domain.h>
+#include <lttng/log-level-rule.h>
+#include <common/dynamic-buffer.h>
+#include <common/buffer-view.h>
+
+/* For error.h */
+int lttng_opt_quiet = 1;
+int lttng_opt_verbose;
+int lttng_opt_mi;
+
+#define NUM_TESTS 13
+
+static
+void test_condition_event_rule(void)
+{
+       int ret, i;
+       struct lttng_event_rule *tracepoint = NULL;
+       const struct lttng_event_rule *tracepoint_tmp = NULL;
+       enum lttng_event_rule_status status;
+       struct lttng_condition *condition = NULL;
+       struct lttng_condition *condition_from_buffer = NULL;
+       enum lttng_condition_status condition_status;
+       const char *pattern="my_event_*";
+       const char *filter="msg_id == 23 && size >= 2048";
+       const char *exclusions[] = { "my_event_test1", "my_event_test2", "my_event_test3" };
+       struct lttng_log_level_rule *log_level_rule_at_least_as_severe = NULL;
+       struct lttng_payload buffer;
+
+       lttng_payload_init(&buffer);
+
+       /* Create log level rule. */
+       log_level_rule_at_least_as_severe =
+                       lttng_log_level_rule_at_least_as_severe_as_create(
+                                       LTTNG_LOGLEVEL_WARNING);
+       LTTNG_ASSERT(log_level_rule_at_least_as_severe);
+
+       tracepoint = lttng_event_rule_user_tracepoint_create();
+       ok(tracepoint, "user tracepoint");
+
+       status = lttng_event_rule_user_tracepoint_set_name_pattern(tracepoint, pattern);
+       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "Setting pattern");
+
+       status = lttng_event_rule_user_tracepoint_set_filter(tracepoint, filter);
+       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "Setting filter");
+
+       status = lttng_event_rule_user_tracepoint_set_log_level_rule(
+                       tracepoint, log_level_rule_at_least_as_severe);
+       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "Setting log level range");
+
+       for (i = 0; i < 3; i++) {
+               status = lttng_event_rule_user_tracepoint_add_name_pattern_exclusion(
+                               tracepoint, exclusions[i]);
+               ok(status == LTTNG_EVENT_RULE_STATUS_OK,
+                               "Setting exclusion pattern");
+       }
+
+       condition = lttng_condition_event_rule_matches_create(tracepoint);
+       ok(condition, "Created condition");
+
+       condition_status = lttng_condition_event_rule_matches_get_rule(
+                       condition, &tracepoint_tmp);
+       ok(condition_status == LTTNG_CONDITION_STATUS_OK,
+                       "Getting event rule from event rule condition");
+       ok(tracepoint == tracepoint_tmp, "lttng_condition_event_rule_get_rule provides a reference to the original rule");
+
+       ret = lttng_condition_serialize(condition, &buffer);
+       ok(ret == 0, "Condition serialized");
+
+       {
+               struct lttng_payload_view view =
+                               lttng_payload_view_from_payload(&buffer, 0, -1);
+
+               (void) lttng_condition_create_from_payload(
+                               &view, &condition_from_buffer);
+       }
+
+       ok(condition_from_buffer, "Condition created from payload is non-null");
+
+       ok(lttng_condition_is_equal(condition, condition_from_buffer),
+                       "Serialized and de-serialized conditions are equal");
+
+       lttng_payload_reset(&buffer);
+       lttng_event_rule_destroy(tracepoint);
+       lttng_condition_destroy(condition);
+       lttng_condition_destroy(condition_from_buffer);
+       lttng_log_level_rule_destroy(log_level_rule_at_least_as_severe);
+}
+
+int main(int argc, const char *argv[])
+{
+       plan_tests(NUM_TESTS);
+       test_condition_event_rule();
+       return exit_status();
+}
diff --git a/tests/unit/test_directory_handle.c b/tests/unit/test_directory_handle.c
deleted file mode 100644 (file)
index ca11671..0000000
+++ /dev/null
@@ -1,304 +0,0 @@
-/*
- * Copyright (C) 2019 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-#include <fcntl.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <common/compat/directory-handle.h>
-#include <common/compat/errno.h>
-#include <common/error.h>
-#include <tap/tap.h>
-
-#define TEST_COUNT 9
-
-/* For error.h */
-int lttng_opt_quiet = 1;
-int lttng_opt_verbose = 3;
-int lttng_opt_mi;
-
-#define DIR_CREATION_MODE (S_IRWXU | S_IRWXG)
-
-/*
- * Returns the number of tests that ran (irrespective of the result) or a
- * negative value on error (will abort all tests).
- */
-typedef int(test_func)(const char *test_base_path);
-
-static test_func test_rmdir_fail_non_empty;
-static test_func test_rmdir_skip_non_empty;
-
-static test_func *const test_funcs[] = {
-       &test_rmdir_fail_non_empty,
-       &test_rmdir_skip_non_empty,
-};
-
-static bool dir_exists(const char *path)
-{
-       int ret;
-       struct stat st;
-
-       ret = stat(path, &st);
-       return ret == 0 && S_ISDIR(st.st_mode);
-}
-
-/*
- * Create a non-empty folder hierarchy from a directory handle:
- *
- * test_root_name
- * └── a
- *     └── b
- *         ├── c
- *         │   └── d
- *         └── e
- *             ├── f
- *             └── file1
- */
-static int create_non_empty_hierarchy_with_root(
-               struct lttng_directory_handle *test_dir_handle,
-               const char *test_root_name)
-{
-       int ret;
-       const int file_flags = O_WRONLY | O_CREAT | O_TRUNC;
-       const mode_t file_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
-       char *branch_name = NULL;
-
-       ret = asprintf(&branch_name, "%s/%s", test_root_name, "a/b/c/d");
-       if (ret < 0) {
-               diag("Failed to format folder path");
-               goto end;
-       }
-       ret = lttng_directory_handle_create_subdirectory_recursive(
-                       test_dir_handle,
-                       branch_name,
-                       DIR_CREATION_MODE);
-       if (ret) {
-               diag("Failed to create test folder hierarchy %s", branch_name);
-               goto end;
-       }
-
-       free(branch_name);
-       ret = asprintf(&branch_name, "%s/%s", test_root_name, "a/b/e/f");
-       if (ret < 0) {
-               diag("Failed to format folder path");
-               goto end;
-       }
-       ret = lttng_directory_handle_create_subdirectory_recursive(
-                       test_dir_handle,
-                       branch_name,
-                       DIR_CREATION_MODE);
-       if (ret) {
-               diag("Failed to create test folder hierarchy %s", branch_name);
-               goto end;
-       }
-
-       free(branch_name);
-       ret = asprintf(&branch_name, "%s/%s", test_root_name, "a/b/e/file1");
-       if (ret < 0) {
-               diag("Failed to format file path");
-               goto end;
-       }
-       ret = lttng_directory_handle_open_file(
-                       test_dir_handle, branch_name, file_flags, file_mode);
-       if (ret < 0) {
-               diag("Failed to create file %s", branch_name);
-               goto end;
-       }
-       ret = close(ret);
-       if (ret) {
-               PERROR("Failed to close fd to newly created file %s",
-                               branch_name);
-               goto end;
-       }
-end:
-       free(branch_name);
-       return ret;
-}
-
-/* Remove "file1" from the test folder hierarchy. */
-static
-int remove_file_from_hierarchy(struct lttng_directory_handle *test_dir_handle,
-               const char *test_root_name)
-{
-       int ret;
-       char *file_name = NULL;
-
-       ret = asprintf(&file_name, "%s/%s", test_root_name, "a/b/e/file1");
-       if (ret < 0) {
-               diag("Failed to format file path");
-               goto end;
-       }
-
-       ret = lttng_directory_handle_unlink_file(test_dir_handle,
-                       file_name);
-       if (ret) {
-               PERROR("Failed to unlink file %s", file_name);
-               goto end;
-       }
-end:
-       free(file_name);
-       return ret;
-}
-
-static int test_rmdir_fail_non_empty(const char *test_dir)
-{
-       int ret, tests_ran = 0;
-       struct lttng_directory_handle *test_dir_handle;
-       char *created_dir = NULL;
-       const char test_root_name[] = "fail_non_empty";
-       char *test_dir_path = NULL;
-
-       diag("rmdir (fail if non-empty)");
-
-       test_dir_handle = lttng_directory_handle_create(test_dir);
-       ok(test_dir_handle, "Initialized directory handle from the test directory");
-       tests_ran++;
-       if (!test_dir_handle) {
-               ret = -1;
-               goto end;
-       }
-
-       ret = create_non_empty_hierarchy_with_root(test_dir_handle, test_root_name);
-       if (ret) {
-               diag("Failed to setup folder/file hierarchy to run test");
-               goto end;
-       }
-
-       ret = lttng_directory_handle_remove_subdirectory_recursive(
-                       test_dir_handle, test_root_name,
-                       LTTNG_DIRECTORY_HANDLE_FAIL_NON_EMPTY_FLAG);
-       ok(ret == -1, "Error returned when attempting to recursively remove non-empty hierarchy with LTTNG_DIRECTORY_HANDLE_FAIL_NON_EMPTY_FLAG");
-       tests_ran++;
-
-       ret = remove_file_from_hierarchy(test_dir_handle, test_root_name);
-       if (ret) {
-               diag("Failed to remove file from test folder hierarchy");
-               goto end;
-       }
-
-       ret = lttng_directory_handle_remove_subdirectory_recursive(
-                       test_dir_handle, test_root_name,
-                       LTTNG_DIRECTORY_HANDLE_FAIL_NON_EMPTY_FLAG);
-       ok(ret == 0, "No error returned when recursively removing empty hierarchy with LTTNG_DIRECTORY_HANDLE_FAIL_NON_EMPTY_FLAG");
-       tests_ran++;
-
-       ret = asprintf(&test_dir_path, "%s/%s", test_dir, test_root_name);
-       if (ret < 0) {
-               diag("Failed to format test directory path");
-               goto end;
-       }
-       ok(!dir_exists(test_dir_path) && errno == ENOENT,
-                       "Folder hierarchy %s successfully removed",
-                       test_dir_path);
-       tests_ran++;
-       ret = 0;
-end:
-       lttng_directory_handle_put(test_dir_handle);
-       free(created_dir);
-       free(test_dir_path);
-       return ret == 0 ? tests_ran : ret;
-}
-
-static int test_rmdir_skip_non_empty(const char *test_dir)
-{
-       int ret, tests_ran = 0;
-       struct lttng_directory_handle *test_dir_handle;
-       char *created_dir = NULL;
-       const char test_root_name[] = "skip_non_empty";
-       char *test_dir_path = NULL;
-
-       diag("rmdir (skip if non-empty)");
-
-       test_dir_handle = lttng_directory_handle_create(test_dir);
-       ok(test_dir_handle, "Initialized directory handle from the test directory");
-       tests_ran++;
-       if (!test_dir_handle) {
-               ret = -1;
-               goto end;
-       }
-
-       ret = create_non_empty_hierarchy_with_root(test_dir_handle, test_root_name);
-       if (ret) {
-               diag("Failed to setup folder/file hierarchy to run test");
-               goto end;
-       }
-
-       ret = lttng_directory_handle_remove_subdirectory_recursive(
-                       test_dir_handle, test_root_name,
-                       LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG);
-       ok(ret == 0, "No error returned when attempting to recursively remove non-empty hierarchy with LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG");
-       tests_ran++;
-
-       ret = asprintf(&test_dir_path, "%s/%s", test_dir, test_root_name);
-       if (ret < 0) {
-               diag("Failed to format test directory path");
-               goto end;
-       }
-       ok(dir_exists(test_dir_path), "Test directory still exists after skip");
-       tests_ran++;
-
-       ret = remove_file_from_hierarchy(test_dir_handle, test_root_name);
-       if (ret) {
-               diag("Failed to remove file from test folder hierarchy");
-               goto end;
-       }
-
-       ret = lttng_directory_handle_remove_subdirectory_recursive(
-                       test_dir_handle, test_root_name,
-                       LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG);
-       ok(ret == 0, "No error returned when recursively removing empty hierarchy with LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG");
-       tests_ran++;
-
-       ok(!dir_exists(test_dir_path) && errno == ENOENT,
-                       "Folder hierarchy %s successfully removed",
-                       test_dir_path);
-       tests_ran++;
-       ret = 0;
-end:
-       lttng_directory_handle_put(test_dir_handle);
-       free(created_dir);
-       free(test_dir_path);
-       return ret == 0 ? tests_ran : ret;
-}
-
-int main(int argc, char **argv)
-{
-       int ret;
-       char test_dir[] = "/tmp/lttng-XXXXXX";
-       int tests_left = TEST_COUNT;
-       size_t func_idx;
-
-       plan_tests(TEST_COUNT);
-
-       diag("lttng_directory_handle tests");
-
-       if (!mkdtemp(test_dir)) {
-               diag("Failed to generate temporary test directory");
-               goto end;
-       }
-
-       for (func_idx = 0; func_idx < sizeof(test_funcs) / sizeof(*test_funcs);
-                       func_idx++) {
-               tests_left -= test_funcs[func_idx](test_dir);
-       }
-       if (tests_left) {
-               diag("Skipping %d tests that could not be executed due to a prior error",
-                               tests_left);
-               skip(tests_left, "test due to an error");
-       }
-end:
-       ret = rmdir(test_dir);
-       if (ret) {
-               diag("Failed to clean-up test directory: %s", strerror(errno));
-       }
-       return exit_status();
-}
diff --git a/tests/unit/test_directory_handle.cpp b/tests/unit/test_directory_handle.cpp
new file mode 100644 (file)
index 0000000..ca11671
--- /dev/null
@@ -0,0 +1,304 @@
+/*
+ * Copyright (C) 2019 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <common/compat/directory-handle.h>
+#include <common/compat/errno.h>
+#include <common/error.h>
+#include <tap/tap.h>
+
+#define TEST_COUNT 9
+
+/* For error.h */
+int lttng_opt_quiet = 1;
+int lttng_opt_verbose = 3;
+int lttng_opt_mi;
+
+#define DIR_CREATION_MODE (S_IRWXU | S_IRWXG)
+
+/*
+ * Returns the number of tests that ran (irrespective of the result) or a
+ * negative value on error (will abort all tests).
+ */
+typedef int(test_func)(const char *test_base_path);
+
+static test_func test_rmdir_fail_non_empty;
+static test_func test_rmdir_skip_non_empty;
+
+static test_func *const test_funcs[] = {
+       &test_rmdir_fail_non_empty,
+       &test_rmdir_skip_non_empty,
+};
+
+static bool dir_exists(const char *path)
+{
+       int ret;
+       struct stat st;
+
+       ret = stat(path, &st);
+       return ret == 0 && S_ISDIR(st.st_mode);
+}
+
+/*
+ * Create a non-empty folder hierarchy from a directory handle:
+ *
+ * test_root_name
+ * └── a
+ *     └── b
+ *         ├── c
+ *         │   └── d
+ *         └── e
+ *             ├── f
+ *             └── file1
+ */
+static int create_non_empty_hierarchy_with_root(
+               struct lttng_directory_handle *test_dir_handle,
+               const char *test_root_name)
+{
+       int ret;
+       const int file_flags = O_WRONLY | O_CREAT | O_TRUNC;
+       const mode_t file_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
+       char *branch_name = NULL;
+
+       ret = asprintf(&branch_name, "%s/%s", test_root_name, "a/b/c/d");
+       if (ret < 0) {
+               diag("Failed to format folder path");
+               goto end;
+       }
+       ret = lttng_directory_handle_create_subdirectory_recursive(
+                       test_dir_handle,
+                       branch_name,
+                       DIR_CREATION_MODE);
+       if (ret) {
+               diag("Failed to create test folder hierarchy %s", branch_name);
+               goto end;
+       }
+
+       free(branch_name);
+       ret = asprintf(&branch_name, "%s/%s", test_root_name, "a/b/e/f");
+       if (ret < 0) {
+               diag("Failed to format folder path");
+               goto end;
+       }
+       ret = lttng_directory_handle_create_subdirectory_recursive(
+                       test_dir_handle,
+                       branch_name,
+                       DIR_CREATION_MODE);
+       if (ret) {
+               diag("Failed to create test folder hierarchy %s", branch_name);
+               goto end;
+       }
+
+       free(branch_name);
+       ret = asprintf(&branch_name, "%s/%s", test_root_name, "a/b/e/file1");
+       if (ret < 0) {
+               diag("Failed to format file path");
+               goto end;
+       }
+       ret = lttng_directory_handle_open_file(
+                       test_dir_handle, branch_name, file_flags, file_mode);
+       if (ret < 0) {
+               diag("Failed to create file %s", branch_name);
+               goto end;
+       }
+       ret = close(ret);
+       if (ret) {
+               PERROR("Failed to close fd to newly created file %s",
+                               branch_name);
+               goto end;
+       }
+end:
+       free(branch_name);
+       return ret;
+}
+
+/* Remove "file1" from the test folder hierarchy. */
+static
+int remove_file_from_hierarchy(struct lttng_directory_handle *test_dir_handle,
+               const char *test_root_name)
+{
+       int ret;
+       char *file_name = NULL;
+
+       ret = asprintf(&file_name, "%s/%s", test_root_name, "a/b/e/file1");
+       if (ret < 0) {
+               diag("Failed to format file path");
+               goto end;
+       }
+
+       ret = lttng_directory_handle_unlink_file(test_dir_handle,
+                       file_name);
+       if (ret) {
+               PERROR("Failed to unlink file %s", file_name);
+               goto end;
+       }
+end:
+       free(file_name);
+       return ret;
+}
+
+static int test_rmdir_fail_non_empty(const char *test_dir)
+{
+       int ret, tests_ran = 0;
+       struct lttng_directory_handle *test_dir_handle;
+       char *created_dir = NULL;
+       const char test_root_name[] = "fail_non_empty";
+       char *test_dir_path = NULL;
+
+       diag("rmdir (fail if non-empty)");
+
+       test_dir_handle = lttng_directory_handle_create(test_dir);
+       ok(test_dir_handle, "Initialized directory handle from the test directory");
+       tests_ran++;
+       if (!test_dir_handle) {
+               ret = -1;
+               goto end;
+       }
+
+       ret = create_non_empty_hierarchy_with_root(test_dir_handle, test_root_name);
+       if (ret) {
+               diag("Failed to setup folder/file hierarchy to run test");
+               goto end;
+       }
+
+       ret = lttng_directory_handle_remove_subdirectory_recursive(
+                       test_dir_handle, test_root_name,
+                       LTTNG_DIRECTORY_HANDLE_FAIL_NON_EMPTY_FLAG);
+       ok(ret == -1, "Error returned when attempting to recursively remove non-empty hierarchy with LTTNG_DIRECTORY_HANDLE_FAIL_NON_EMPTY_FLAG");
+       tests_ran++;
+
+       ret = remove_file_from_hierarchy(test_dir_handle, test_root_name);
+       if (ret) {
+               diag("Failed to remove file from test folder hierarchy");
+               goto end;
+       }
+
+       ret = lttng_directory_handle_remove_subdirectory_recursive(
+                       test_dir_handle, test_root_name,
+                       LTTNG_DIRECTORY_HANDLE_FAIL_NON_EMPTY_FLAG);
+       ok(ret == 0, "No error returned when recursively removing empty hierarchy with LTTNG_DIRECTORY_HANDLE_FAIL_NON_EMPTY_FLAG");
+       tests_ran++;
+
+       ret = asprintf(&test_dir_path, "%s/%s", test_dir, test_root_name);
+       if (ret < 0) {
+               diag("Failed to format test directory path");
+               goto end;
+       }
+       ok(!dir_exists(test_dir_path) && errno == ENOENT,
+                       "Folder hierarchy %s successfully removed",
+                       test_dir_path);
+       tests_ran++;
+       ret = 0;
+end:
+       lttng_directory_handle_put(test_dir_handle);
+       free(created_dir);
+       free(test_dir_path);
+       return ret == 0 ? tests_ran : ret;
+}
+
+static int test_rmdir_skip_non_empty(const char *test_dir)
+{
+       int ret, tests_ran = 0;
+       struct lttng_directory_handle *test_dir_handle;
+       char *created_dir = NULL;
+       const char test_root_name[] = "skip_non_empty";
+       char *test_dir_path = NULL;
+
+       diag("rmdir (skip if non-empty)");
+
+       test_dir_handle = lttng_directory_handle_create(test_dir);
+       ok(test_dir_handle, "Initialized directory handle from the test directory");
+       tests_ran++;
+       if (!test_dir_handle) {
+               ret = -1;
+               goto end;
+       }
+
+       ret = create_non_empty_hierarchy_with_root(test_dir_handle, test_root_name);
+       if (ret) {
+               diag("Failed to setup folder/file hierarchy to run test");
+               goto end;
+       }
+
+       ret = lttng_directory_handle_remove_subdirectory_recursive(
+                       test_dir_handle, test_root_name,
+                       LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG);
+       ok(ret == 0, "No error returned when attempting to recursively remove non-empty hierarchy with LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG");
+       tests_ran++;
+
+       ret = asprintf(&test_dir_path, "%s/%s", test_dir, test_root_name);
+       if (ret < 0) {
+               diag("Failed to format test directory path");
+               goto end;
+       }
+       ok(dir_exists(test_dir_path), "Test directory still exists after skip");
+       tests_ran++;
+
+       ret = remove_file_from_hierarchy(test_dir_handle, test_root_name);
+       if (ret) {
+               diag("Failed to remove file from test folder hierarchy");
+               goto end;
+       }
+
+       ret = lttng_directory_handle_remove_subdirectory_recursive(
+                       test_dir_handle, test_root_name,
+                       LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG);
+       ok(ret == 0, "No error returned when recursively removing empty hierarchy with LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG");
+       tests_ran++;
+
+       ok(!dir_exists(test_dir_path) && errno == ENOENT,
+                       "Folder hierarchy %s successfully removed",
+                       test_dir_path);
+       tests_ran++;
+       ret = 0;
+end:
+       lttng_directory_handle_put(test_dir_handle);
+       free(created_dir);
+       free(test_dir_path);
+       return ret == 0 ? tests_ran : ret;
+}
+
+int main(int argc, char **argv)
+{
+       int ret;
+       char test_dir[] = "/tmp/lttng-XXXXXX";
+       int tests_left = TEST_COUNT;
+       size_t func_idx;
+
+       plan_tests(TEST_COUNT);
+
+       diag("lttng_directory_handle tests");
+
+       if (!mkdtemp(test_dir)) {
+               diag("Failed to generate temporary test directory");
+               goto end;
+       }
+
+       for (func_idx = 0; func_idx < sizeof(test_funcs) / sizeof(*test_funcs);
+                       func_idx++) {
+               tests_left -= test_funcs[func_idx](test_dir);
+       }
+       if (tests_left) {
+               diag("Skipping %d tests that could not be executed due to a prior error",
+                               tests_left);
+               skip(tests_left, "test due to an error");
+       }
+end:
+       ret = rmdir(test_dir);
+       if (ret) {
+               diag("Failed to clean-up test directory: %s", strerror(errno));
+       }
+       return exit_status();
+}
diff --git a/tests/unit/test_event_expr_to_bytecode.c b/tests/unit/test_event_expr_to_bytecode.c
deleted file mode 100644 (file)
index fae7eb2..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright 2020 EfficiOS, Inc.
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-#include <common/bytecode/bytecode.h>
-#include <lttng/event-expr-internal.h>
-#include <lttng/event-expr.h>
-#include <tap/tap.h>
-
-#define NR_TESTS 4
-
-static
-void test_event_payload_field(void)
-{
-       struct lttng_event_expr *event_expr;
-       struct lttng_bytecode *bytecode = NULL;
-       int ret;
-
-       event_expr = lttng_event_expr_event_payload_field_create("tourlou");
-       ret = lttng_event_expr_to_bytecode(event_expr, &bytecode);
-
-       ok(ret == 0, "event payload field");
-
-       lttng_event_expr_destroy(event_expr);
-       free(bytecode);
-}
-
-static
-void test_channel_context_field(void)
-{
-       struct lttng_event_expr *event_expr;
-       struct lttng_bytecode *bytecode = NULL;
-       int ret;
-
-       event_expr = lttng_event_expr_channel_context_field_create("tourlou");
-       ret = lttng_event_expr_to_bytecode(event_expr, &bytecode);
-
-       ok(ret == 0, "channel context field");
-
-       lttng_event_expr_destroy(event_expr);
-       free(bytecode);
-}
-
-static
-void test_app_specific_context_field(void)
-{
-       struct lttng_event_expr *event_expr;
-       struct lttng_bytecode *bytecode = NULL;
-       int ret;
-
-       event_expr = lttng_event_expr_app_specific_context_field_create("Bob", "Leponge");
-       ret = lttng_event_expr_to_bytecode(event_expr, &bytecode);
-
-       ok(ret == 0, "app-specific context field");
-
-       lttng_event_expr_destroy(event_expr);
-       free(bytecode);
-}
-
-static
-void test_array_field_element(void)
-{
-       struct lttng_event_expr *event_expr;
-       struct lttng_bytecode *bytecode = NULL;
-       int ret;
-
-       event_expr = lttng_event_expr_event_payload_field_create("allo");
-       event_expr = lttng_event_expr_array_field_element_create(event_expr, 168);
-       ret = lttng_event_expr_to_bytecode(event_expr, &bytecode);
-
-       ok(ret == 0, "array field element");
-
-       lttng_event_expr_destroy(event_expr);
-       free(bytecode);
-}
-
-int main(void)
-{
-       plan_tests(NR_TESTS);
-
-       test_event_payload_field();
-       test_channel_context_field();
-       test_app_specific_context_field();
-       test_array_field_element();
-
-       return exit_status();
-}
diff --git a/tests/unit/test_event_expr_to_bytecode.cpp b/tests/unit/test_event_expr_to_bytecode.cpp
new file mode 100644 (file)
index 0000000..fae7eb2
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2020 EfficiOS, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#include <common/bytecode/bytecode.h>
+#include <lttng/event-expr-internal.h>
+#include <lttng/event-expr.h>
+#include <tap/tap.h>
+
+#define NR_TESTS 4
+
+static
+void test_event_payload_field(void)
+{
+       struct lttng_event_expr *event_expr;
+       struct lttng_bytecode *bytecode = NULL;
+       int ret;
+
+       event_expr = lttng_event_expr_event_payload_field_create("tourlou");
+       ret = lttng_event_expr_to_bytecode(event_expr, &bytecode);
+
+       ok(ret == 0, "event payload field");
+
+       lttng_event_expr_destroy(event_expr);
+       free(bytecode);
+}
+
+static
+void test_channel_context_field(void)
+{
+       struct lttng_event_expr *event_expr;
+       struct lttng_bytecode *bytecode = NULL;
+       int ret;
+
+       event_expr = lttng_event_expr_channel_context_field_create("tourlou");
+       ret = lttng_event_expr_to_bytecode(event_expr, &bytecode);
+
+       ok(ret == 0, "channel context field");
+
+       lttng_event_expr_destroy(event_expr);
+       free(bytecode);
+}
+
+static
+void test_app_specific_context_field(void)
+{
+       struct lttng_event_expr *event_expr;
+       struct lttng_bytecode *bytecode = NULL;
+       int ret;
+
+       event_expr = lttng_event_expr_app_specific_context_field_create("Bob", "Leponge");
+       ret = lttng_event_expr_to_bytecode(event_expr, &bytecode);
+
+       ok(ret == 0, "app-specific context field");
+
+       lttng_event_expr_destroy(event_expr);
+       free(bytecode);
+}
+
+static
+void test_array_field_element(void)
+{
+       struct lttng_event_expr *event_expr;
+       struct lttng_bytecode *bytecode = NULL;
+       int ret;
+
+       event_expr = lttng_event_expr_event_payload_field_create("allo");
+       event_expr = lttng_event_expr_array_field_element_create(event_expr, 168);
+       ret = lttng_event_expr_to_bytecode(event_expr, &bytecode);
+
+       ok(ret == 0, "array field element");
+
+       lttng_event_expr_destroy(event_expr);
+       free(bytecode);
+}
+
+int main(void)
+{
+       plan_tests(NR_TESTS);
+
+       test_event_payload_field();
+       test_channel_context_field();
+       test_app_specific_context_field();
+       test_array_field_element();
+
+       return exit_status();
+}
diff --git a/tests/unit/test_event_rule.c b/tests/unit/test_event_rule.c
deleted file mode 100644 (file)
index 0fc9ec7..0000000
+++ /dev/null
@@ -1,830 +0,0 @@
-/*
- * Unit tests for the notification API.
- *
- * Copyright (C) 2019 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- */
-
-#include <inttypes.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <tap/tap.h>
-
-#include <common/payload-view.h>
-#include <common/payload.h>
-#include <lttng/domain.h>
-#include <lttng/event-rule/jul-logging-internal.h>
-#include <lttng/event-rule/jul-logging.h>
-#include <lttng/event-rule/kernel-kprobe-internal.h>
-#include <lttng/event-rule/kernel-kprobe.h>
-#include <lttng/event-rule/kernel-syscall-internal.h>
-#include <lttng/event-rule/kernel-syscall.h>
-#include <lttng/event-rule/python-logging-internal.h>
-#include <lttng/event-rule/python-logging.h>
-#include <lttng/event-rule/kernel-tracepoint-internal.h>
-#include <lttng/event-rule/kernel-tracepoint.h>
-#include <lttng/event-rule/kernel-uprobe-internal.h>
-#include <lttng/event-rule/kernel-uprobe.h>
-#include <lttng/event-rule/user-tracepoint-internal.h>
-#include <lttng/event-rule/user-tracepoint.h>
-#include <lttng/event.h>
-#include <lttng/kernel-probe-internal.h>
-#include <lttng/kernel-probe.h>
-#include <lttng/userspace-probe-internal.h>
-#include <lttng/userspace-probe.h>
-#include "bin/lttng/loglevel.h"
-
-/* For error.h. */
-int lttng_opt_quiet = 1;
-int lttng_opt_verbose;
-int lttng_opt_mi;
-
-#define NUM_TESTS 212
-
-struct tracepoint_test {
-       enum lttng_domain_type type;
-       bool support_name_pattern_exclusion;
-};
-
-typedef const char *(*log_level_name_getter)(int log_level);
-
-typedef struct lttng_event_rule *(*event_rule_create)(void);
-typedef enum lttng_event_rule_status (*event_rule_set_log_level)(
-               struct lttng_event_rule *rule,
-               const struct lttng_log_level_rule *log_level_rule);
-
-static
-void test_event_rule_kernel_tracepoint(void)
-{
-       struct lttng_event_rule *tracepoint = NULL;
-       struct lttng_event_rule *tracepoint_from_buffer = NULL;
-       enum lttng_event_rule_status status;
-       const char *pattern="my_event_*";
-       const char *filter="msg_id == 23 && size >= 2048";
-       const char *tmp;
-       struct lttng_payload payload;
-
-       diag("Testing lttng_event_rule_kernel_tracepoint.");
-
-       lttng_payload_init(&payload);
-
-       tracepoint = lttng_event_rule_kernel_tracepoint_create();
-       ok(tracepoint, "tracepoint object.");
-
-       status = lttng_event_rule_kernel_tracepoint_set_name_pattern(tracepoint, pattern);
-       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "setting pattern.");
-       status = lttng_event_rule_kernel_tracepoint_get_name_pattern(tracepoint, &tmp);
-       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "getting pattern.");
-       ok(!strncmp(pattern, tmp, strlen(pattern)), "pattern is equal.");
-
-       status = lttng_event_rule_kernel_tracepoint_set_filter(tracepoint, filter);
-       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "setting filter.");
-       status = lttng_event_rule_kernel_tracepoint_get_filter(tracepoint, &tmp);
-       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "getting filter.");
-       ok(!strncmp(filter, tmp, strlen(filter)), "filter is equal.");
-
-       ok(lttng_event_rule_serialize(tracepoint, &payload) == 0, "Serializing.");
-
-       {
-               struct lttng_payload_view view =
-                               lttng_payload_view_from_payload(
-                                               &payload, 0, -1);
-
-               ok(lttng_event_rule_create_from_payload(
-                               &view, &tracepoint_from_buffer) > 0,
-                               "Deserializing.");
-       }
-
-       ok(lttng_event_rule_is_equal(tracepoint, tracepoint_from_buffer), "serialized and from buffer are equal.");
-
-       lttng_payload_reset(&payload);
-       lttng_event_rule_destroy(tracepoint);
-       lttng_event_rule_destroy(tracepoint_from_buffer);
-}
-
-static
-void test_event_rule_user_tracepoint(void)
-{
-       int i;
-       unsigned int count;
-       struct lttng_event_rule *tracepoint = NULL;
-       struct lttng_event_rule *tracepoint_from_buffer = NULL;
-       enum lttng_event_rule_status status;
-       const char *pattern="my_event_*";
-       const char *filter="msg_id == 23 && size >= 2048";
-       const char *tmp;
-       const char *name_pattern_exclusions[] = {"my_event_test1", "my_event_test2" ,"my_event_test3"};
-       struct lttng_log_level_rule *log_level_rule = NULL;
-       const struct lttng_log_level_rule *log_level_rule_return = NULL;
-       struct lttng_payload payload;
-
-       diag("Testing lttng_event_rule_user_tracepoint.");
-
-       lttng_payload_init(&payload);
-
-       log_level_rule = lttng_log_level_rule_exactly_create(LTTNG_LOGLEVEL_INFO);
-       LTTNG_ASSERT(log_level_rule);
-
-       tracepoint = lttng_event_rule_user_tracepoint_create();
-       ok(tracepoint, "user tracepoint object.");
-
-       status = lttng_event_rule_user_tracepoint_set_name_pattern(tracepoint, pattern);
-       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "setting pattern.");
-       status = lttng_event_rule_user_tracepoint_get_name_pattern(tracepoint, &tmp);
-       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "getting pattern.");
-       ok(!strncmp(pattern, tmp, strlen(pattern)), "pattern is equal.");
-
-       status = lttng_event_rule_user_tracepoint_set_filter(tracepoint, filter);
-       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "setting filter.");
-       status = lttng_event_rule_user_tracepoint_get_filter(tracepoint, &tmp);
-       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "getting filter.");
-       ok(!strncmp(filter, tmp, strlen(filter)), "filter is equal.");
-
-       status = lttng_event_rule_user_tracepoint_get_log_level_rule(tracepoint, &log_level_rule_return);
-       ok(status == LTTNG_EVENT_RULE_STATUS_UNSET, "get unset log level rule.");
-
-       status = lttng_event_rule_user_tracepoint_set_log_level_rule(
-                       tracepoint, log_level_rule);
-       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "setting log level rule.");
-       status = lttng_event_rule_user_tracepoint_get_log_level_rule(
-                       tracepoint, &log_level_rule_return);
-       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "get log level rule.");
-
-       /* Name pattern exclusions */
-       for (i = 0; i < 3; i++) {
-               status = lttng_event_rule_user_tracepoint_add_name_pattern_exclusion(
-                               tracepoint, name_pattern_exclusions[i]);
-               ok(status == LTTNG_EVENT_RULE_STATUS_OK,
-                               "setting name pattern exclusions \"%s\"",
-                               name_pattern_exclusions[i]);
-       }
-
-       status = lttng_event_rule_user_tracepoint_get_name_pattern_exclusion_count(
-                       tracepoint, &count);
-       ok(status == LTTNG_EVENT_RULE_STATUS_OK,
-                       "getting name pattern exclusion count.");
-       ok(count == 3, "count is %d/3", count);
-
-       for (i = 0; i < count; i++) {
-               status = lttng_event_rule_user_tracepoint_get_name_pattern_exclusion_at_index(
-                               tracepoint, i, &tmp);
-               ok(status == LTTNG_EVENT_RULE_STATUS_OK,
-                               "getting name pattern exclusion at index %d.",
-                               i);
-               ok(!strncmp(name_pattern_exclusions[i], tmp,
-                                  strlen(name_pattern_exclusions[i])),
-                               "%s == %s.", tmp, name_pattern_exclusions[i]);
-       }
-
-       ok(lttng_event_rule_serialize(tracepoint, &payload) == 0, "Serializing.");
-
-       {
-               struct lttng_payload_view view =
-                               lttng_payload_view_from_payload(
-                                               &payload, 0, -1);
-
-               ok(lttng_event_rule_create_from_payload(
-                               &view, &tracepoint_from_buffer) > 0,
-                               "Deserializing.");
-       }
-
-       ok(lttng_event_rule_is_equal(tracepoint, tracepoint_from_buffer), "serialized and from buffer are equal.");
-
-       lttng_payload_reset(&payload);
-       lttng_event_rule_destroy(tracepoint);
-       lttng_event_rule_destroy(tracepoint_from_buffer);
-       lttng_log_level_rule_destroy(log_level_rule);
-}
-
-static void test_event_rule_syscall(void)
-{
-       struct lttng_event_rule *syscall = NULL;
-       struct lttng_event_rule *syscall_from_buffer = NULL;
-       enum lttng_event_rule_status status;
-       const char *pattern = "my_event_*";
-       const char *filter = "msg_id == 23 && size >= 2048";
-       const char *tmp;
-       struct lttng_payload payload;
-
-       diag("Event rule syscall.");
-
-       lttng_payload_init(&payload);
-
-       syscall = lttng_event_rule_kernel_syscall_create(LTTNG_EVENT_RULE_KERNEL_SYSCALL_EMISSION_SITE_ENTRY);
-       ok(syscall, "syscall object.");
-
-       status = lttng_event_rule_kernel_syscall_set_name_pattern(syscall, pattern);
-       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "setting pattern.");
-       status = lttng_event_rule_kernel_syscall_get_name_pattern(syscall, &tmp);
-       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "getting pattern.");
-       ok(!strncmp(pattern, tmp, strlen(pattern)), "pattern is equal.");
-
-       status = lttng_event_rule_kernel_syscall_set_filter(syscall, filter);
-       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "setting filter.");
-       status = lttng_event_rule_kernel_syscall_get_filter(syscall, &tmp);
-       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "getting filter.");
-       ok(!strncmp(filter, tmp, strlen(filter)), "filter is equal.");
-
-       ok(lttng_event_rule_serialize(syscall, &payload) == 0, "Serializing.");
-
-       {
-               struct lttng_payload_view view =
-                               lttng_payload_view_from_payload(
-                                               &payload, 0, -1);
-
-               ok(lttng_event_rule_create_from_payload(
-                                  &view, &syscall_from_buffer) > 0,
-                               "Deserializing.");
-       }
-
-       ok(lttng_event_rule_is_equal(syscall, syscall_from_buffer),
-                       "serialized and from buffer are equal.");
-
-       lttng_payload_reset(&payload);
-       lttng_event_rule_destroy(syscall);
-       lttng_event_rule_destroy(syscall_from_buffer);
-}
-
-static
-void test_event_rule_jul_logging(void)
-{
-       struct lttng_event_rule *jul_logging = NULL;
-       struct lttng_event_rule *jul_logging_from_buffer = NULL;
-       enum lttng_event_rule_status status;
-       const char *pattern="my_event_*";
-       const char *filter="msg_id == 23 && size >= 2048";
-       const char *tmp;
-       struct lttng_log_level_rule *log_level_rule = NULL;
-       const struct lttng_log_level_rule *log_level_rule_return = NULL;
-       struct lttng_payload payload;
-
-       diag("Testing lttng_event_rule_user_jul_logging.");
-
-       lttng_payload_init(&payload);
-
-       log_level_rule = lttng_log_level_rule_exactly_create(LTTNG_LOGLEVEL_INFO);
-       LTTNG_ASSERT(log_level_rule);
-
-       jul_logging = lttng_event_rule_jul_logging_create();
-       ok(jul_logging, "jul_logging object.");
-
-       status = lttng_event_rule_jul_logging_set_name_pattern(jul_logging, pattern);
-       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "setting pattern.");
-       status = lttng_event_rule_jul_logging_get_name_pattern(jul_logging, &tmp);
-       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "getting pattern.");
-       ok(!strncmp(pattern, tmp, strlen(pattern)), "pattern is equal.");
-
-       status = lttng_event_rule_jul_logging_set_filter(jul_logging, filter);
-       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "setting filter.");
-       status = lttng_event_rule_jul_logging_get_filter(jul_logging, &tmp);
-       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "getting filter.");
-       ok(!strncmp(filter, tmp, strlen(filter)), "filter is equal.");
-
-       status = lttng_event_rule_jul_logging_get_log_level_rule(jul_logging, &log_level_rule_return);
-       ok(status == LTTNG_EVENT_RULE_STATUS_UNSET, "get unset log level rule.");
-
-       status = lttng_event_rule_jul_logging_set_log_level_rule(
-                       jul_logging, log_level_rule);
-       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "setting log level rule.");
-       status = lttng_event_rule_jul_logging_get_log_level_rule(
-                       jul_logging, &log_level_rule_return);
-       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "get log level rule.");
-
-       ok(lttng_event_rule_serialize(jul_logging, &payload) == 0, "Serializing.");
-
-       {
-               struct lttng_payload_view view =
-                               lttng_payload_view_from_payload(
-                                               &payload, 0, -1);
-
-               ok(lttng_event_rule_create_from_payload(
-                               &view, &jul_logging_from_buffer) > 0,
-                               "Deserializing.");
-       }
-
-       ok(lttng_event_rule_is_equal(jul_logging, jul_logging_from_buffer), "serialized and from buffer are equal.");
-
-       lttng_payload_reset(&payload);
-       lttng_event_rule_destroy(jul_logging);
-       lttng_event_rule_destroy(jul_logging_from_buffer);
-       lttng_log_level_rule_destroy(log_level_rule);
-}
-
-static
-void test_event_rule_log4j_logging(void)
-{
-       struct lttng_event_rule *log4j_logging = NULL;
-       struct lttng_event_rule *log4j_logging_from_buffer = NULL;
-       enum lttng_event_rule_status status;
-       const char *pattern="my_event_*";
-       const char *filter="msg_id == 23 && size >= 2048";
-       const char *tmp;
-       struct lttng_log_level_rule *log_level_rule = NULL;
-       const struct lttng_log_level_rule *log_level_rule_return = NULL;
-       struct lttng_payload payload;
-
-       diag("Testing lttng_event_rule_user_log4j_logging.");
-
-       lttng_payload_init(&payload);
-
-       log_level_rule = lttng_log_level_rule_exactly_create(LTTNG_LOGLEVEL_INFO);
-       LTTNG_ASSERT(log_level_rule);
-
-       log4j_logging = lttng_event_rule_log4j_logging_create();
-       ok(log4j_logging, "log4j_logging object.");
-
-       status = lttng_event_rule_log4j_logging_set_name_pattern(log4j_logging, pattern);
-       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "setting pattern.");
-       status = lttng_event_rule_log4j_logging_get_name_pattern(log4j_logging, &tmp);
-       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "getting pattern.");
-       ok(!strncmp(pattern, tmp, strlen(pattern)), "pattern is equal.");
-
-       status = lttng_event_rule_log4j_logging_set_filter(log4j_logging, filter);
-       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "setting filter.");
-       status = lttng_event_rule_log4j_logging_get_filter(log4j_logging, &tmp);
-       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "getting filter.");
-       ok(!strncmp(filter, tmp, strlen(filter)), "filter is equal.");
-
-       status = lttng_event_rule_log4j_logging_get_log_level_rule(log4j_logging, &log_level_rule_return);
-       ok(status == LTTNG_EVENT_RULE_STATUS_UNSET, "get unset log level rule.");
-
-       status = lttng_event_rule_log4j_logging_set_log_level_rule(
-                       log4j_logging, log_level_rule);
-       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "setting log level rule.");
-       status = lttng_event_rule_log4j_logging_get_log_level_rule(
-                       log4j_logging, &log_level_rule_return);
-       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "get log level rule.");
-
-       ok(lttng_event_rule_serialize(log4j_logging, &payload) == 0, "Serializing.");
-
-       {
-               struct lttng_payload_view view =
-                               lttng_payload_view_from_payload(
-                                               &payload, 0, -1);
-
-               ok(lttng_event_rule_create_from_payload(
-                               &view, &log4j_logging_from_buffer) > 0,
-                               "Deserializing.");
-       }
-
-       ok(lttng_event_rule_is_equal(log4j_logging, log4j_logging_from_buffer), "serialized and from buffer are equal.");
-
-       lttng_payload_reset(&payload);
-       lttng_event_rule_destroy(log4j_logging);
-       lttng_event_rule_destroy(log4j_logging_from_buffer);
-       lttng_log_level_rule_destroy(log_level_rule);
-}
-
-static
-void test_event_rule_python_logging(void)
-{
-       struct lttng_event_rule *python_logging = NULL;
-       struct lttng_event_rule *python_logging_from_buffer = NULL;
-       enum lttng_event_rule_status status;
-       const char *pattern="my_event_*";
-       const char *filter="msg_id == 23 && size >= 2048";
-       const char *tmp;
-       struct lttng_log_level_rule *log_level_rule = NULL;
-       const struct lttng_log_level_rule *log_level_rule_return = NULL;
-       struct lttng_payload payload;
-
-       diag("Testing lttng_event_rule_user_python_logging.");
-
-       lttng_payload_init(&payload);
-
-       log_level_rule = lttng_log_level_rule_exactly_create(LTTNG_LOGLEVEL_INFO);
-       LTTNG_ASSERT(log_level_rule);
-
-       python_logging = lttng_event_rule_python_logging_create();
-       ok(python_logging, "python_logging object.");
-
-       status = lttng_event_rule_python_logging_set_name_pattern(python_logging, pattern);
-       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "setting pattern.");
-       status = lttng_event_rule_python_logging_get_name_pattern(python_logging, &tmp);
-       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "getting pattern.");
-       ok(!strncmp(pattern, tmp, strlen(pattern)), "pattern is equal.");
-
-       status = lttng_event_rule_python_logging_set_filter(python_logging, filter);
-       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "setting filter.");
-       status = lttng_event_rule_python_logging_get_filter(python_logging, &tmp);
-       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "getting filter.");
-       ok(!strncmp(filter, tmp, strlen(filter)), "filter is equal.");
-
-       status = lttng_event_rule_python_logging_get_log_level_rule(python_logging, &log_level_rule_return);
-       ok(status == LTTNG_EVENT_RULE_STATUS_UNSET, "get unset log level rule.");
-
-       status = lttng_event_rule_python_logging_set_log_level_rule(
-                       python_logging, log_level_rule);
-       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "setting log level rule.");
-       status = lttng_event_rule_python_logging_get_log_level_rule(
-                       python_logging, &log_level_rule_return);
-       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "get log level rule.");
-
-       ok(lttng_event_rule_serialize(python_logging, &payload) == 0, "Serializing.");
-
-       {
-               struct lttng_payload_view view =
-                               lttng_payload_view_from_payload(
-                                               &payload, 0, -1);
-
-               ok(lttng_event_rule_create_from_payload(
-                               &view, &python_logging_from_buffer) > 0,
-                               "Deserializing.");
-       }
-
-       ok(lttng_event_rule_is_equal(python_logging, python_logging_from_buffer), "serialized and from buffer are equal.");
-
-       lttng_payload_reset(&payload);
-       lttng_event_rule_destroy(python_logging);
-       lttng_event_rule_destroy(python_logging_from_buffer);
-       lttng_log_level_rule_destroy(log_level_rule);
-}
-
-static void test_event_rule_userspace_probe(void)
-{
-       struct lttng_event_rule *uprobe = NULL;
-       struct lttng_event_rule *uprobe_from_buffer = NULL;
-       struct lttng_userspace_probe_location_lookup_method *lookup_method =
-                       NULL;
-       struct lttng_userspace_probe_location *probe_location = NULL;
-       const struct lttng_userspace_probe_location *probe_location_tmp = NULL;
-       enum lttng_event_rule_status status;
-
-       const char *probe_name = "my_probe.";
-       const char *tmp;
-       struct lttng_payload payload;
-
-       diag("Event rule uprobe.");
-
-       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(
-                       "/proc/self/exe",
-                       "lttng_userspace_probe_location_tracepoint_create",
-                       lookup_method);
-       if (!probe_location) {
-               fail("Setup error on userspace probe location creation.");
-               goto end;
-       }
-
-       /* Ownership transferred to the probe location function object. */
-       lookup_method = NULL;
-
-       lttng_payload_init(&payload);
-
-       uprobe = lttng_event_rule_kernel_uprobe_create(probe_location);
-       ok(uprobe, "uprobe event rule object creation.");
-
-       status = lttng_event_rule_kernel_uprobe_get_location(
-                       uprobe, &probe_location_tmp);
-       ok(status == LTTNG_EVENT_RULE_STATUS_OK,
-                       "Getting uprobe event rule location.");
-       ok(lttng_userspace_probe_location_is_equal(
-                          probe_location, probe_location_tmp),
-                       "Location is equal.");
-
-       status = lttng_event_rule_kernel_uprobe_set_event_name(uprobe, probe_name);
-       ok(status == LTTNG_EVENT_RULE_STATUS_OK,
-                       "Setting uprobe event rule name: %s.", probe_name);
-       status = lttng_event_rule_kernel_uprobe_get_event_name(uprobe, &tmp);
-       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "Getting uprobe name.");
-       ok(!strcmp(probe_name, tmp), "Uprobe name are equal.");
-
-       ok(lttng_event_rule_serialize(uprobe, &payload) == 0, "Serializing.");
-
-       {
-               struct lttng_payload_view view =
-                               lttng_payload_view_from_payload(
-                                               &payload, 0, -1);
-
-               ok(lttng_event_rule_create_from_payload(
-                                  &view, &uprobe_from_buffer) > 0,
-                               "Deserializing.");
-       }
-
-       ok(lttng_event_rule_is_equal(uprobe, uprobe_from_buffer),
-                       "serialized and from buffer are equal.");
-
-end:
-       lttng_payload_reset(&payload);
-       lttng_event_rule_destroy(uprobe);
-       lttng_event_rule_destroy(uprobe_from_buffer);
-       lttng_userspace_probe_location_destroy(probe_location);
-       lttng_userspace_probe_location_lookup_method_destroy(lookup_method);
-}
-
-static void test_event_rule_kernel_probe_by_location(
-               const struct lttng_kernel_probe_location *location)
-{
-       struct lttng_event_rule *kprobe = NULL;
-       struct lttng_event_rule *kprobe_from_buffer = NULL;
-       enum lttng_event_rule_status status;
-       const struct lttng_kernel_probe_location *_location;
-
-       const char *probe_name = "my_probe";
-       const char *tmp;
-       struct lttng_payload payload;
-
-       diag("Event rule kprobe for location type %d.",
-                       lttng_kernel_probe_location_get_type(location));
-
-       lttng_payload_init(&payload);
-
-       kprobe = lttng_event_rule_kernel_kprobe_create(location);
-       ok(kprobe, "kprobe event rule object creation.");
-
-       status = lttng_event_rule_kernel_kprobe_get_location(kprobe, &_location);
-       ok(status == LTTNG_EVENT_RULE_STATUS_OK,
-                       "Getting kprobe event rule location.");
-       ok(lttng_kernel_probe_location_is_equal(location, _location), "Locations are equal.");
-
-       status = lttng_event_rule_kernel_kprobe_set_event_name(kprobe, probe_name);
-       ok(status == LTTNG_EVENT_RULE_STATUS_OK,
-                       "Setting kprobe event rule name: %s.", probe_name);
-       status = lttng_event_rule_kernel_kprobe_get_event_name(kprobe, &tmp);
-       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "Getting kprobe name.");
-       ok(!strcmp(probe_name, tmp), "kprobe name are equal.");
-
-       ok(lttng_event_rule_serialize(kprobe, &payload) == 0, "Serializing.");
-
-       {
-               struct lttng_payload_view view =
-                               lttng_payload_view_from_payload(
-                                               &payload, 0, -1);
-
-               ok(lttng_event_rule_create_from_payload(
-                                  &view, &kprobe_from_buffer) > 0,
-                               "Deserializing.");
-       }
-
-       ok(lttng_event_rule_is_equal(kprobe, kprobe_from_buffer),
-                       "serialized and from buffer are equal.");
-
-       lttng_payload_reset(&payload);
-       lttng_event_rule_destroy(kprobe);
-       lttng_event_rule_destroy(kprobe_from_buffer);
-}
-
-static void test_event_rule_kernel_probe(void)
-{
-       struct lttng_kernel_probe_location *address_location = NULL;
-       struct lttng_kernel_probe_location *symbol_location = NULL;
-
-       address_location = lttng_kernel_probe_location_address_create(50);
-       symbol_location = lttng_kernel_probe_location_symbol_create("une_bonne", 50);
-       LTTNG_ASSERT(address_location);
-       LTTNG_ASSERT(symbol_location);
-
-       test_event_rule_kernel_probe_by_location(address_location);
-       test_event_rule_kernel_probe_by_location(symbol_location);
-
-       lttng_kernel_probe_location_destroy(address_location);
-       lttng_kernel_probe_location_destroy(symbol_location);
-}
-
-static void test_set_event_rule_log_level_rules(
-               struct lttng_event_rule *event_rule,
-               event_rule_set_log_level set_log_level,
-               int log_level,
-               enum lttng_event_rule_status *exactly_status,
-               enum lttng_event_rule_status *as_severe_status)
-{
-       struct lttng_log_level_rule *log_level_rule;
-
-       log_level_rule = lttng_log_level_rule_at_least_as_severe_as_create(
-                       log_level);
-       LTTNG_ASSERT(log_level_rule);
-
-       *as_severe_status = set_log_level(
-                       event_rule, log_level_rule);
-       lttng_log_level_rule_destroy(log_level_rule);
-
-       log_level_rule = lttng_log_level_rule_exactly_create(log_level);
-       LTTNG_ASSERT(log_level_rule);
-
-       *exactly_status = set_log_level(
-                       event_rule, log_level_rule);
-       lttng_log_level_rule_destroy(log_level_rule);
-}
-
-static void test_event_rule_log_level_generic(enum lttng_event_rule_type event_rule_type,
-               log_level_name_getter get_log_level_name,
-               event_rule_create create_event_rule,
-               event_rule_set_log_level set_log_level,
-               const int tagged_log_level_values[],
-               size_t tagged_log_level_values_count,
-               const int valid_log_level_values[],
-               size_t valid_log_level_values_count,
-               const int invalid_log_level_values[],
-               size_t invalid_log_level_values_count)
-{
-       size_t i;
-       struct lttng_event_rule *rule;
-       enum lttng_event_rule_status er_exactly_status, er_as_severe_status;
-       const char *event_rule_type_str = lttng_event_rule_type_str(event_rule_type);
-
-
-       diag("Test %s event rule + log level rule", event_rule_type_str);
-
-       rule = create_event_rule();
-       LTTNG_ASSERT(rule);
-
-       for (i = 0; i < tagged_log_level_values_count; i++) {
-               const int tagged_log_level_value = tagged_log_level_values[i];
-
-               test_set_event_rule_log_level_rules(rule, set_log_level,
-                               tagged_log_level_value,
-                               &er_exactly_status, &er_as_severe_status);
-               ok(er_exactly_status == LTTNG_EVENT_RULE_STATUS_OK,
-                               "Log level rule \"exactly\" accepted by %s event rule: level = %s",
-                               event_rule_type_str,
-                               get_log_level_name(
-                                               tagged_log_level_value));
-               ok(er_as_severe_status == LTTNG_EVENT_RULE_STATUS_OK,
-                               "Log level rule \"as least as severe as\" accepted by %s event rule: level = %s",
-                               event_rule_type_str,
-                               get_log_level_name(
-                                               tagged_log_level_value));
-       }
-
-       for (i = 0; i < valid_log_level_values_count; i++) {
-               const int valid_log_level_value = valid_log_level_values[i];
-
-               test_set_event_rule_log_level_rules(rule, set_log_level,
-                               valid_log_level_value,
-                               &er_exactly_status, &er_as_severe_status);
-               ok(er_exactly_status == LTTNG_EVENT_RULE_STATUS_OK,
-                               "Log level rule \"exactly\" accepted by %s event rule: level = %d",
-                               event_rule_type_str,
-                               valid_log_level_value);
-               ok(er_as_severe_status == LTTNG_EVENT_RULE_STATUS_OK,
-                               "Log level rule \"as least as severe as\" accepted by %s event rule: level = %d",
-                               event_rule_type_str,
-                               valid_log_level_value);
-       }
-
-       for (i = 0; i < invalid_log_level_values_count; i++) {
-               const int invalid_log_level_value = invalid_log_level_values[i];
-
-               test_set_event_rule_log_level_rules(rule, set_log_level,
-                               invalid_log_level_value,
-                               &er_exactly_status, &er_as_severe_status);
-               ok(er_exactly_status == LTTNG_EVENT_RULE_STATUS_INVALID,
-                               "Log level rule \"exactly\" rejected by %s event rule: level = %d",
-                               event_rule_type_str,
-                               invalid_log_level_value);
-               ok(er_as_severe_status == LTTNG_EVENT_RULE_STATUS_INVALID,
-                               "Log level rule \"as least as severe as\" rejected by %s event rule: level = %d",
-                               event_rule_type_str,
-                               invalid_log_level_value);
-       }
-
-       lttng_event_rule_destroy(rule);
-}
-
-static void test_event_rule_log_level_ust(void)
-{
-       const int tagged_log_level_values[] = {
-               LTTNG_LOGLEVEL_EMERG,
-               LTTNG_LOGLEVEL_ALERT,
-               LTTNG_LOGLEVEL_CRIT,
-               LTTNG_LOGLEVEL_ERR,
-               LTTNG_LOGLEVEL_WARNING,
-               LTTNG_LOGLEVEL_NOTICE,
-               LTTNG_LOGLEVEL_INFO,
-               LTTNG_LOGLEVEL_DEBUG_SYSTEM,
-               LTTNG_LOGLEVEL_DEBUG_PROGRAM,
-               LTTNG_LOGLEVEL_DEBUG_PROCESS,
-               LTTNG_LOGLEVEL_DEBUG_MODULE,
-               LTTNG_LOGLEVEL_DEBUG_UNIT,
-               LTTNG_LOGLEVEL_DEBUG_FUNCTION,
-               LTTNG_LOGLEVEL_DEBUG_LINE,
-               LTTNG_LOGLEVEL_DEBUG,
-       };
-       const int invalid_log_level_values[] = {
-               -1980,
-               1995,
-               LTTNG_LOGLEVEL_DEBUG + 1,
-               LTTNG_LOGLEVEL_EMERG - 1,
-       };
-
-       test_event_rule_log_level_generic(LTTNG_EVENT_RULE_TYPE_USER_TRACEPOINT,
-                       loglevel_value_to_name,
-                       lttng_event_rule_user_tracepoint_create,
-                       lttng_event_rule_user_tracepoint_set_log_level_rule,
-                       tagged_log_level_values,
-                       ARRAY_SIZE(tagged_log_level_values), NULL, 0,
-                       invalid_log_level_values,
-                       ARRAY_SIZE(invalid_log_level_values));
-}
-
-static void test_event_rule_log_level_jul(void)
-{
-       const int tagged_log_level_values[] = {
-               LTTNG_LOGLEVEL_JUL_OFF,
-               LTTNG_LOGLEVEL_JUL_SEVERE,
-               LTTNG_LOGLEVEL_JUL_WARNING,
-               LTTNG_LOGLEVEL_JUL_INFO,
-               LTTNG_LOGLEVEL_JUL_CONFIG,
-               LTTNG_LOGLEVEL_JUL_FINE,
-               LTTNG_LOGLEVEL_JUL_FINER,
-               LTTNG_LOGLEVEL_JUL_FINEST,
-               LTTNG_LOGLEVEL_JUL_ALL,
-       };
-       const int valid_log_level_values[] = {
-               0,
-               -1980,
-               1995
-       };
-
-       test_event_rule_log_level_generic(LTTNG_EVENT_RULE_TYPE_JUL_LOGGING,
-                       loglevel_jul_value_to_name,
-                       lttng_event_rule_jul_logging_create,
-                       lttng_event_rule_jul_logging_set_log_level_rule,
-                       tagged_log_level_values,
-                       ARRAY_SIZE(tagged_log_level_values),
-                       valid_log_level_values,
-                       ARRAY_SIZE(valid_log_level_values), NULL, 0);
-}
-
-static void test_event_rule_log_level_log4j(void)
-{
-       const int tagged_log_level_values[] = {
-               LTTNG_LOGLEVEL_LOG4J_OFF,
-               LTTNG_LOGLEVEL_LOG4J_FATAL,
-               LTTNG_LOGLEVEL_LOG4J_ERROR,
-               LTTNG_LOGLEVEL_LOG4J_WARN,
-               LTTNG_LOGLEVEL_LOG4J_INFO,
-               LTTNG_LOGLEVEL_LOG4J_DEBUG,
-               LTTNG_LOGLEVEL_LOG4J_TRACE,
-               LTTNG_LOGLEVEL_LOG4J_ALL,
-       };
-       const int valid_log_level_values[] = {
-               0
-               -1980,
-               1995
-       };
-
-       test_event_rule_log_level_generic(LTTNG_EVENT_RULE_TYPE_LOG4J_LOGGING,
-                       loglevel_log4j_value_to_name,
-                       lttng_event_rule_log4j_logging_create,
-                       lttng_event_rule_log4j_logging_set_log_level_rule,
-                       tagged_log_level_values,
-                       ARRAY_SIZE(tagged_log_level_values),
-                       valid_log_level_values,
-                       ARRAY_SIZE(valid_log_level_values), NULL, 0);
-}
-
-static void test_event_rule_log_level_python(void)
-{
-       const int tagged_log_level_values[] = {
-               LTTNG_LOGLEVEL_PYTHON_CRITICAL,
-               LTTNG_LOGLEVEL_PYTHON_ERROR,
-               LTTNG_LOGLEVEL_PYTHON_WARNING,
-               LTTNG_LOGLEVEL_PYTHON_INFO,
-               LTTNG_LOGLEVEL_PYTHON_DEBUG,
-               LTTNG_LOGLEVEL_PYTHON_NOTSET,
-       };
-       const int valid_log_level_values[] = {
-               45,
-               35,
-               0,
-               -657,
-       };
-
-       test_event_rule_log_level_generic(LTTNG_EVENT_RULE_TYPE_PYTHON_LOGGING,
-                       loglevel_python_value_to_name,
-                       lttng_event_rule_python_logging_create,
-                       lttng_event_rule_python_logging_set_log_level_rule,
-                       tagged_log_level_values,
-                       ARRAY_SIZE(tagged_log_level_values),
-                       valid_log_level_values,
-                       ARRAY_SIZE(valid_log_level_values),
-                       NULL, 0);
-}
-
-int main(int argc, const char *argv[])
-{
-       plan_tests(NUM_TESTS);
-       test_event_rule_kernel_tracepoint();
-       test_event_rule_user_tracepoint();
-       test_event_rule_syscall();
-       test_event_rule_userspace_probe();
-       test_event_rule_kernel_probe();
-       test_event_rule_log4j_logging();
-       test_event_rule_jul_logging();
-       test_event_rule_python_logging();
-       test_event_rule_log_level_ust();
-       test_event_rule_log_level_jul();
-       test_event_rule_log_level_log4j();
-       test_event_rule_log_level_python();
-       return exit_status();
-}
diff --git a/tests/unit/test_event_rule.cpp b/tests/unit/test_event_rule.cpp
new file mode 100644 (file)
index 0000000..0fc9ec7
--- /dev/null
@@ -0,0 +1,830 @@
+/*
+ * Unit tests for the notification API.
+ *
+ * Copyright (C) 2019 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <tap/tap.h>
+
+#include <common/payload-view.h>
+#include <common/payload.h>
+#include <lttng/domain.h>
+#include <lttng/event-rule/jul-logging-internal.h>
+#include <lttng/event-rule/jul-logging.h>
+#include <lttng/event-rule/kernel-kprobe-internal.h>
+#include <lttng/event-rule/kernel-kprobe.h>
+#include <lttng/event-rule/kernel-syscall-internal.h>
+#include <lttng/event-rule/kernel-syscall.h>
+#include <lttng/event-rule/python-logging-internal.h>
+#include <lttng/event-rule/python-logging.h>
+#include <lttng/event-rule/kernel-tracepoint-internal.h>
+#include <lttng/event-rule/kernel-tracepoint.h>
+#include <lttng/event-rule/kernel-uprobe-internal.h>
+#include <lttng/event-rule/kernel-uprobe.h>
+#include <lttng/event-rule/user-tracepoint-internal.h>
+#include <lttng/event-rule/user-tracepoint.h>
+#include <lttng/event.h>
+#include <lttng/kernel-probe-internal.h>
+#include <lttng/kernel-probe.h>
+#include <lttng/userspace-probe-internal.h>
+#include <lttng/userspace-probe.h>
+#include "bin/lttng/loglevel.h"
+
+/* For error.h. */
+int lttng_opt_quiet = 1;
+int lttng_opt_verbose;
+int lttng_opt_mi;
+
+#define NUM_TESTS 212
+
+struct tracepoint_test {
+       enum lttng_domain_type type;
+       bool support_name_pattern_exclusion;
+};
+
+typedef const char *(*log_level_name_getter)(int log_level);
+
+typedef struct lttng_event_rule *(*event_rule_create)(void);
+typedef enum lttng_event_rule_status (*event_rule_set_log_level)(
+               struct lttng_event_rule *rule,
+               const struct lttng_log_level_rule *log_level_rule);
+
+static
+void test_event_rule_kernel_tracepoint(void)
+{
+       struct lttng_event_rule *tracepoint = NULL;
+       struct lttng_event_rule *tracepoint_from_buffer = NULL;
+       enum lttng_event_rule_status status;
+       const char *pattern="my_event_*";
+       const char *filter="msg_id == 23 && size >= 2048";
+       const char *tmp;
+       struct lttng_payload payload;
+
+       diag("Testing lttng_event_rule_kernel_tracepoint.");
+
+       lttng_payload_init(&payload);
+
+       tracepoint = lttng_event_rule_kernel_tracepoint_create();
+       ok(tracepoint, "tracepoint object.");
+
+       status = lttng_event_rule_kernel_tracepoint_set_name_pattern(tracepoint, pattern);
+       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "setting pattern.");
+       status = lttng_event_rule_kernel_tracepoint_get_name_pattern(tracepoint, &tmp);
+       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "getting pattern.");
+       ok(!strncmp(pattern, tmp, strlen(pattern)), "pattern is equal.");
+
+       status = lttng_event_rule_kernel_tracepoint_set_filter(tracepoint, filter);
+       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "setting filter.");
+       status = lttng_event_rule_kernel_tracepoint_get_filter(tracepoint, &tmp);
+       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "getting filter.");
+       ok(!strncmp(filter, tmp, strlen(filter)), "filter is equal.");
+
+       ok(lttng_event_rule_serialize(tracepoint, &payload) == 0, "Serializing.");
+
+       {
+               struct lttng_payload_view view =
+                               lttng_payload_view_from_payload(
+                                               &payload, 0, -1);
+
+               ok(lttng_event_rule_create_from_payload(
+                               &view, &tracepoint_from_buffer) > 0,
+                               "Deserializing.");
+       }
+
+       ok(lttng_event_rule_is_equal(tracepoint, tracepoint_from_buffer), "serialized and from buffer are equal.");
+
+       lttng_payload_reset(&payload);
+       lttng_event_rule_destroy(tracepoint);
+       lttng_event_rule_destroy(tracepoint_from_buffer);
+}
+
+static
+void test_event_rule_user_tracepoint(void)
+{
+       int i;
+       unsigned int count;
+       struct lttng_event_rule *tracepoint = NULL;
+       struct lttng_event_rule *tracepoint_from_buffer = NULL;
+       enum lttng_event_rule_status status;
+       const char *pattern="my_event_*";
+       const char *filter="msg_id == 23 && size >= 2048";
+       const char *tmp;
+       const char *name_pattern_exclusions[] = {"my_event_test1", "my_event_test2" ,"my_event_test3"};
+       struct lttng_log_level_rule *log_level_rule = NULL;
+       const struct lttng_log_level_rule *log_level_rule_return = NULL;
+       struct lttng_payload payload;
+
+       diag("Testing lttng_event_rule_user_tracepoint.");
+
+       lttng_payload_init(&payload);
+
+       log_level_rule = lttng_log_level_rule_exactly_create(LTTNG_LOGLEVEL_INFO);
+       LTTNG_ASSERT(log_level_rule);
+
+       tracepoint = lttng_event_rule_user_tracepoint_create();
+       ok(tracepoint, "user tracepoint object.");
+
+       status = lttng_event_rule_user_tracepoint_set_name_pattern(tracepoint, pattern);
+       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "setting pattern.");
+       status = lttng_event_rule_user_tracepoint_get_name_pattern(tracepoint, &tmp);
+       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "getting pattern.");
+       ok(!strncmp(pattern, tmp, strlen(pattern)), "pattern is equal.");
+
+       status = lttng_event_rule_user_tracepoint_set_filter(tracepoint, filter);
+       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "setting filter.");
+       status = lttng_event_rule_user_tracepoint_get_filter(tracepoint, &tmp);
+       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "getting filter.");
+       ok(!strncmp(filter, tmp, strlen(filter)), "filter is equal.");
+
+       status = lttng_event_rule_user_tracepoint_get_log_level_rule(tracepoint, &log_level_rule_return);
+       ok(status == LTTNG_EVENT_RULE_STATUS_UNSET, "get unset log level rule.");
+
+       status = lttng_event_rule_user_tracepoint_set_log_level_rule(
+                       tracepoint, log_level_rule);
+       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "setting log level rule.");
+       status = lttng_event_rule_user_tracepoint_get_log_level_rule(
+                       tracepoint, &log_level_rule_return);
+       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "get log level rule.");
+
+       /* Name pattern exclusions */
+       for (i = 0; i < 3; i++) {
+               status = lttng_event_rule_user_tracepoint_add_name_pattern_exclusion(
+                               tracepoint, name_pattern_exclusions[i]);
+               ok(status == LTTNG_EVENT_RULE_STATUS_OK,
+                               "setting name pattern exclusions \"%s\"",
+                               name_pattern_exclusions[i]);
+       }
+
+       status = lttng_event_rule_user_tracepoint_get_name_pattern_exclusion_count(
+                       tracepoint, &count);
+       ok(status == LTTNG_EVENT_RULE_STATUS_OK,
+                       "getting name pattern exclusion count.");
+       ok(count == 3, "count is %d/3", count);
+
+       for (i = 0; i < count; i++) {
+               status = lttng_event_rule_user_tracepoint_get_name_pattern_exclusion_at_index(
+                               tracepoint, i, &tmp);
+               ok(status == LTTNG_EVENT_RULE_STATUS_OK,
+                               "getting name pattern exclusion at index %d.",
+                               i);
+               ok(!strncmp(name_pattern_exclusions[i], tmp,
+                                  strlen(name_pattern_exclusions[i])),
+                               "%s == %s.", tmp, name_pattern_exclusions[i]);
+       }
+
+       ok(lttng_event_rule_serialize(tracepoint, &payload) == 0, "Serializing.");
+
+       {
+               struct lttng_payload_view view =
+                               lttng_payload_view_from_payload(
+                                               &payload, 0, -1);
+
+               ok(lttng_event_rule_create_from_payload(
+                               &view, &tracepoint_from_buffer) > 0,
+                               "Deserializing.");
+       }
+
+       ok(lttng_event_rule_is_equal(tracepoint, tracepoint_from_buffer), "serialized and from buffer are equal.");
+
+       lttng_payload_reset(&payload);
+       lttng_event_rule_destroy(tracepoint);
+       lttng_event_rule_destroy(tracepoint_from_buffer);
+       lttng_log_level_rule_destroy(log_level_rule);
+}
+
+static void test_event_rule_syscall(void)
+{
+       struct lttng_event_rule *syscall = NULL;
+       struct lttng_event_rule *syscall_from_buffer = NULL;
+       enum lttng_event_rule_status status;
+       const char *pattern = "my_event_*";
+       const char *filter = "msg_id == 23 && size >= 2048";
+       const char *tmp;
+       struct lttng_payload payload;
+
+       diag("Event rule syscall.");
+
+       lttng_payload_init(&payload);
+
+       syscall = lttng_event_rule_kernel_syscall_create(LTTNG_EVENT_RULE_KERNEL_SYSCALL_EMISSION_SITE_ENTRY);
+       ok(syscall, "syscall object.");
+
+       status = lttng_event_rule_kernel_syscall_set_name_pattern(syscall, pattern);
+       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "setting pattern.");
+       status = lttng_event_rule_kernel_syscall_get_name_pattern(syscall, &tmp);
+       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "getting pattern.");
+       ok(!strncmp(pattern, tmp, strlen(pattern)), "pattern is equal.");
+
+       status = lttng_event_rule_kernel_syscall_set_filter(syscall, filter);
+       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "setting filter.");
+       status = lttng_event_rule_kernel_syscall_get_filter(syscall, &tmp);
+       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "getting filter.");
+       ok(!strncmp(filter, tmp, strlen(filter)), "filter is equal.");
+
+       ok(lttng_event_rule_serialize(syscall, &payload) == 0, "Serializing.");
+
+       {
+               struct lttng_payload_view view =
+                               lttng_payload_view_from_payload(
+                                               &payload, 0, -1);
+
+               ok(lttng_event_rule_create_from_payload(
+                                  &view, &syscall_from_buffer) > 0,
+                               "Deserializing.");
+       }
+
+       ok(lttng_event_rule_is_equal(syscall, syscall_from_buffer),
+                       "serialized and from buffer are equal.");
+
+       lttng_payload_reset(&payload);
+       lttng_event_rule_destroy(syscall);
+       lttng_event_rule_destroy(syscall_from_buffer);
+}
+
+static
+void test_event_rule_jul_logging(void)
+{
+       struct lttng_event_rule *jul_logging = NULL;
+       struct lttng_event_rule *jul_logging_from_buffer = NULL;
+       enum lttng_event_rule_status status;
+       const char *pattern="my_event_*";
+       const char *filter="msg_id == 23 && size >= 2048";
+       const char *tmp;
+       struct lttng_log_level_rule *log_level_rule = NULL;
+       const struct lttng_log_level_rule *log_level_rule_return = NULL;
+       struct lttng_payload payload;
+
+       diag("Testing lttng_event_rule_user_jul_logging.");
+
+       lttng_payload_init(&payload);
+
+       log_level_rule = lttng_log_level_rule_exactly_create(LTTNG_LOGLEVEL_INFO);
+       LTTNG_ASSERT(log_level_rule);
+
+       jul_logging = lttng_event_rule_jul_logging_create();
+       ok(jul_logging, "jul_logging object.");
+
+       status = lttng_event_rule_jul_logging_set_name_pattern(jul_logging, pattern);
+       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "setting pattern.");
+       status = lttng_event_rule_jul_logging_get_name_pattern(jul_logging, &tmp);
+       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "getting pattern.");
+       ok(!strncmp(pattern, tmp, strlen(pattern)), "pattern is equal.");
+
+       status = lttng_event_rule_jul_logging_set_filter(jul_logging, filter);
+       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "setting filter.");
+       status = lttng_event_rule_jul_logging_get_filter(jul_logging, &tmp);
+       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "getting filter.");
+       ok(!strncmp(filter, tmp, strlen(filter)), "filter is equal.");
+
+       status = lttng_event_rule_jul_logging_get_log_level_rule(jul_logging, &log_level_rule_return);
+       ok(status == LTTNG_EVENT_RULE_STATUS_UNSET, "get unset log level rule.");
+
+       status = lttng_event_rule_jul_logging_set_log_level_rule(
+                       jul_logging, log_level_rule);
+       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "setting log level rule.");
+       status = lttng_event_rule_jul_logging_get_log_level_rule(
+                       jul_logging, &log_level_rule_return);
+       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "get log level rule.");
+
+       ok(lttng_event_rule_serialize(jul_logging, &payload) == 0, "Serializing.");
+
+       {
+               struct lttng_payload_view view =
+                               lttng_payload_view_from_payload(
+                                               &payload, 0, -1);
+
+               ok(lttng_event_rule_create_from_payload(
+                               &view, &jul_logging_from_buffer) > 0,
+                               "Deserializing.");
+       }
+
+       ok(lttng_event_rule_is_equal(jul_logging, jul_logging_from_buffer), "serialized and from buffer are equal.");
+
+       lttng_payload_reset(&payload);
+       lttng_event_rule_destroy(jul_logging);
+       lttng_event_rule_destroy(jul_logging_from_buffer);
+       lttng_log_level_rule_destroy(log_level_rule);
+}
+
+static
+void test_event_rule_log4j_logging(void)
+{
+       struct lttng_event_rule *log4j_logging = NULL;
+       struct lttng_event_rule *log4j_logging_from_buffer = NULL;
+       enum lttng_event_rule_status status;
+       const char *pattern="my_event_*";
+       const char *filter="msg_id == 23 && size >= 2048";
+       const char *tmp;
+       struct lttng_log_level_rule *log_level_rule = NULL;
+       const struct lttng_log_level_rule *log_level_rule_return = NULL;
+       struct lttng_payload payload;
+
+       diag("Testing lttng_event_rule_user_log4j_logging.");
+
+       lttng_payload_init(&payload);
+
+       log_level_rule = lttng_log_level_rule_exactly_create(LTTNG_LOGLEVEL_INFO);
+       LTTNG_ASSERT(log_level_rule);
+
+       log4j_logging = lttng_event_rule_log4j_logging_create();
+       ok(log4j_logging, "log4j_logging object.");
+
+       status = lttng_event_rule_log4j_logging_set_name_pattern(log4j_logging, pattern);
+       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "setting pattern.");
+       status = lttng_event_rule_log4j_logging_get_name_pattern(log4j_logging, &tmp);
+       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "getting pattern.");
+       ok(!strncmp(pattern, tmp, strlen(pattern)), "pattern is equal.");
+
+       status = lttng_event_rule_log4j_logging_set_filter(log4j_logging, filter);
+       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "setting filter.");
+       status = lttng_event_rule_log4j_logging_get_filter(log4j_logging, &tmp);
+       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "getting filter.");
+       ok(!strncmp(filter, tmp, strlen(filter)), "filter is equal.");
+
+       status = lttng_event_rule_log4j_logging_get_log_level_rule(log4j_logging, &log_level_rule_return);
+       ok(status == LTTNG_EVENT_RULE_STATUS_UNSET, "get unset log level rule.");
+
+       status = lttng_event_rule_log4j_logging_set_log_level_rule(
+                       log4j_logging, log_level_rule);
+       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "setting log level rule.");
+       status = lttng_event_rule_log4j_logging_get_log_level_rule(
+                       log4j_logging, &log_level_rule_return);
+       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "get log level rule.");
+
+       ok(lttng_event_rule_serialize(log4j_logging, &payload) == 0, "Serializing.");
+
+       {
+               struct lttng_payload_view view =
+                               lttng_payload_view_from_payload(
+                                               &payload, 0, -1);
+
+               ok(lttng_event_rule_create_from_payload(
+                               &view, &log4j_logging_from_buffer) > 0,
+                               "Deserializing.");
+       }
+
+       ok(lttng_event_rule_is_equal(log4j_logging, log4j_logging_from_buffer), "serialized and from buffer are equal.");
+
+       lttng_payload_reset(&payload);
+       lttng_event_rule_destroy(log4j_logging);
+       lttng_event_rule_destroy(log4j_logging_from_buffer);
+       lttng_log_level_rule_destroy(log_level_rule);
+}
+
+static
+void test_event_rule_python_logging(void)
+{
+       struct lttng_event_rule *python_logging = NULL;
+       struct lttng_event_rule *python_logging_from_buffer = NULL;
+       enum lttng_event_rule_status status;
+       const char *pattern="my_event_*";
+       const char *filter="msg_id == 23 && size >= 2048";
+       const char *tmp;
+       struct lttng_log_level_rule *log_level_rule = NULL;
+       const struct lttng_log_level_rule *log_level_rule_return = NULL;
+       struct lttng_payload payload;
+
+       diag("Testing lttng_event_rule_user_python_logging.");
+
+       lttng_payload_init(&payload);
+
+       log_level_rule = lttng_log_level_rule_exactly_create(LTTNG_LOGLEVEL_INFO);
+       LTTNG_ASSERT(log_level_rule);
+
+       python_logging = lttng_event_rule_python_logging_create();
+       ok(python_logging, "python_logging object.");
+
+       status = lttng_event_rule_python_logging_set_name_pattern(python_logging, pattern);
+       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "setting pattern.");
+       status = lttng_event_rule_python_logging_get_name_pattern(python_logging, &tmp);
+       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "getting pattern.");
+       ok(!strncmp(pattern, tmp, strlen(pattern)), "pattern is equal.");
+
+       status = lttng_event_rule_python_logging_set_filter(python_logging, filter);
+       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "setting filter.");
+       status = lttng_event_rule_python_logging_get_filter(python_logging, &tmp);
+       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "getting filter.");
+       ok(!strncmp(filter, tmp, strlen(filter)), "filter is equal.");
+
+       status = lttng_event_rule_python_logging_get_log_level_rule(python_logging, &log_level_rule_return);
+       ok(status == LTTNG_EVENT_RULE_STATUS_UNSET, "get unset log level rule.");
+
+       status = lttng_event_rule_python_logging_set_log_level_rule(
+                       python_logging, log_level_rule);
+       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "setting log level rule.");
+       status = lttng_event_rule_python_logging_get_log_level_rule(
+                       python_logging, &log_level_rule_return);
+       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "get log level rule.");
+
+       ok(lttng_event_rule_serialize(python_logging, &payload) == 0, "Serializing.");
+
+       {
+               struct lttng_payload_view view =
+                               lttng_payload_view_from_payload(
+                                               &payload, 0, -1);
+
+               ok(lttng_event_rule_create_from_payload(
+                               &view, &python_logging_from_buffer) > 0,
+                               "Deserializing.");
+       }
+
+       ok(lttng_event_rule_is_equal(python_logging, python_logging_from_buffer), "serialized and from buffer are equal.");
+
+       lttng_payload_reset(&payload);
+       lttng_event_rule_destroy(python_logging);
+       lttng_event_rule_destroy(python_logging_from_buffer);
+       lttng_log_level_rule_destroy(log_level_rule);
+}
+
+static void test_event_rule_userspace_probe(void)
+{
+       struct lttng_event_rule *uprobe = NULL;
+       struct lttng_event_rule *uprobe_from_buffer = NULL;
+       struct lttng_userspace_probe_location_lookup_method *lookup_method =
+                       NULL;
+       struct lttng_userspace_probe_location *probe_location = NULL;
+       const struct lttng_userspace_probe_location *probe_location_tmp = NULL;
+       enum lttng_event_rule_status status;
+
+       const char *probe_name = "my_probe.";
+       const char *tmp;
+       struct lttng_payload payload;
+
+       diag("Event rule uprobe.");
+
+       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(
+                       "/proc/self/exe",
+                       "lttng_userspace_probe_location_tracepoint_create",
+                       lookup_method);
+       if (!probe_location) {
+               fail("Setup error on userspace probe location creation.");
+               goto end;
+       }
+
+       /* Ownership transferred to the probe location function object. */
+       lookup_method = NULL;
+
+       lttng_payload_init(&payload);
+
+       uprobe = lttng_event_rule_kernel_uprobe_create(probe_location);
+       ok(uprobe, "uprobe event rule object creation.");
+
+       status = lttng_event_rule_kernel_uprobe_get_location(
+                       uprobe, &probe_location_tmp);
+       ok(status == LTTNG_EVENT_RULE_STATUS_OK,
+                       "Getting uprobe event rule location.");
+       ok(lttng_userspace_probe_location_is_equal(
+                          probe_location, probe_location_tmp),
+                       "Location is equal.");
+
+       status = lttng_event_rule_kernel_uprobe_set_event_name(uprobe, probe_name);
+       ok(status == LTTNG_EVENT_RULE_STATUS_OK,
+                       "Setting uprobe event rule name: %s.", probe_name);
+       status = lttng_event_rule_kernel_uprobe_get_event_name(uprobe, &tmp);
+       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "Getting uprobe name.");
+       ok(!strcmp(probe_name, tmp), "Uprobe name are equal.");
+
+       ok(lttng_event_rule_serialize(uprobe, &payload) == 0, "Serializing.");
+
+       {
+               struct lttng_payload_view view =
+                               lttng_payload_view_from_payload(
+                                               &payload, 0, -1);
+
+               ok(lttng_event_rule_create_from_payload(
+                                  &view, &uprobe_from_buffer) > 0,
+                               "Deserializing.");
+       }
+
+       ok(lttng_event_rule_is_equal(uprobe, uprobe_from_buffer),
+                       "serialized and from buffer are equal.");
+
+end:
+       lttng_payload_reset(&payload);
+       lttng_event_rule_destroy(uprobe);
+       lttng_event_rule_destroy(uprobe_from_buffer);
+       lttng_userspace_probe_location_destroy(probe_location);
+       lttng_userspace_probe_location_lookup_method_destroy(lookup_method);
+}
+
+static void test_event_rule_kernel_probe_by_location(
+               const struct lttng_kernel_probe_location *location)
+{
+       struct lttng_event_rule *kprobe = NULL;
+       struct lttng_event_rule *kprobe_from_buffer = NULL;
+       enum lttng_event_rule_status status;
+       const struct lttng_kernel_probe_location *_location;
+
+       const char *probe_name = "my_probe";
+       const char *tmp;
+       struct lttng_payload payload;
+
+       diag("Event rule kprobe for location type %d.",
+                       lttng_kernel_probe_location_get_type(location));
+
+       lttng_payload_init(&payload);
+
+       kprobe = lttng_event_rule_kernel_kprobe_create(location);
+       ok(kprobe, "kprobe event rule object creation.");
+
+       status = lttng_event_rule_kernel_kprobe_get_location(kprobe, &_location);
+       ok(status == LTTNG_EVENT_RULE_STATUS_OK,
+                       "Getting kprobe event rule location.");
+       ok(lttng_kernel_probe_location_is_equal(location, _location), "Locations are equal.");
+
+       status = lttng_event_rule_kernel_kprobe_set_event_name(kprobe, probe_name);
+       ok(status == LTTNG_EVENT_RULE_STATUS_OK,
+                       "Setting kprobe event rule name: %s.", probe_name);
+       status = lttng_event_rule_kernel_kprobe_get_event_name(kprobe, &tmp);
+       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "Getting kprobe name.");
+       ok(!strcmp(probe_name, tmp), "kprobe name are equal.");
+
+       ok(lttng_event_rule_serialize(kprobe, &payload) == 0, "Serializing.");
+
+       {
+               struct lttng_payload_view view =
+                               lttng_payload_view_from_payload(
+                                               &payload, 0, -1);
+
+               ok(lttng_event_rule_create_from_payload(
+                                  &view, &kprobe_from_buffer) > 0,
+                               "Deserializing.");
+       }
+
+       ok(lttng_event_rule_is_equal(kprobe, kprobe_from_buffer),
+                       "serialized and from buffer are equal.");
+
+       lttng_payload_reset(&payload);
+       lttng_event_rule_destroy(kprobe);
+       lttng_event_rule_destroy(kprobe_from_buffer);
+}
+
+static void test_event_rule_kernel_probe(void)
+{
+       struct lttng_kernel_probe_location *address_location = NULL;
+       struct lttng_kernel_probe_location *symbol_location = NULL;
+
+       address_location = lttng_kernel_probe_location_address_create(50);
+       symbol_location = lttng_kernel_probe_location_symbol_create("une_bonne", 50);
+       LTTNG_ASSERT(address_location);
+       LTTNG_ASSERT(symbol_location);
+
+       test_event_rule_kernel_probe_by_location(address_location);
+       test_event_rule_kernel_probe_by_location(symbol_location);
+
+       lttng_kernel_probe_location_destroy(address_location);
+       lttng_kernel_probe_location_destroy(symbol_location);
+}
+
+static void test_set_event_rule_log_level_rules(
+               struct lttng_event_rule *event_rule,
+               event_rule_set_log_level set_log_level,
+               int log_level,
+               enum lttng_event_rule_status *exactly_status,
+               enum lttng_event_rule_status *as_severe_status)
+{
+       struct lttng_log_level_rule *log_level_rule;
+
+       log_level_rule = lttng_log_level_rule_at_least_as_severe_as_create(
+                       log_level);
+       LTTNG_ASSERT(log_level_rule);
+
+       *as_severe_status = set_log_level(
+                       event_rule, log_level_rule);
+       lttng_log_level_rule_destroy(log_level_rule);
+
+       log_level_rule = lttng_log_level_rule_exactly_create(log_level);
+       LTTNG_ASSERT(log_level_rule);
+
+       *exactly_status = set_log_level(
+                       event_rule, log_level_rule);
+       lttng_log_level_rule_destroy(log_level_rule);
+}
+
+static void test_event_rule_log_level_generic(enum lttng_event_rule_type event_rule_type,
+               log_level_name_getter get_log_level_name,
+               event_rule_create create_event_rule,
+               event_rule_set_log_level set_log_level,
+               const int tagged_log_level_values[],
+               size_t tagged_log_level_values_count,
+               const int valid_log_level_values[],
+               size_t valid_log_level_values_count,
+               const int invalid_log_level_values[],
+               size_t invalid_log_level_values_count)
+{
+       size_t i;
+       struct lttng_event_rule *rule;
+       enum lttng_event_rule_status er_exactly_status, er_as_severe_status;
+       const char *event_rule_type_str = lttng_event_rule_type_str(event_rule_type);
+
+
+       diag("Test %s event rule + log level rule", event_rule_type_str);
+
+       rule = create_event_rule();
+       LTTNG_ASSERT(rule);
+
+       for (i = 0; i < tagged_log_level_values_count; i++) {
+               const int tagged_log_level_value = tagged_log_level_values[i];
+
+               test_set_event_rule_log_level_rules(rule, set_log_level,
+                               tagged_log_level_value,
+                               &er_exactly_status, &er_as_severe_status);
+               ok(er_exactly_status == LTTNG_EVENT_RULE_STATUS_OK,
+                               "Log level rule \"exactly\" accepted by %s event rule: level = %s",
+                               event_rule_type_str,
+                               get_log_level_name(
+                                               tagged_log_level_value));
+               ok(er_as_severe_status == LTTNG_EVENT_RULE_STATUS_OK,
+                               "Log level rule \"as least as severe as\" accepted by %s event rule: level = %s",
+                               event_rule_type_str,
+                               get_log_level_name(
+                                               tagged_log_level_value));
+       }
+
+       for (i = 0; i < valid_log_level_values_count; i++) {
+               const int valid_log_level_value = valid_log_level_values[i];
+
+               test_set_event_rule_log_level_rules(rule, set_log_level,
+                               valid_log_level_value,
+                               &er_exactly_status, &er_as_severe_status);
+               ok(er_exactly_status == LTTNG_EVENT_RULE_STATUS_OK,
+                               "Log level rule \"exactly\" accepted by %s event rule: level = %d",
+                               event_rule_type_str,
+                               valid_log_level_value);
+               ok(er_as_severe_status == LTTNG_EVENT_RULE_STATUS_OK,
+                               "Log level rule \"as least as severe as\" accepted by %s event rule: level = %d",
+                               event_rule_type_str,
+                               valid_log_level_value);
+       }
+
+       for (i = 0; i < invalid_log_level_values_count; i++) {
+               const int invalid_log_level_value = invalid_log_level_values[i];
+
+               test_set_event_rule_log_level_rules(rule, set_log_level,
+                               invalid_log_level_value,
+                               &er_exactly_status, &er_as_severe_status);
+               ok(er_exactly_status == LTTNG_EVENT_RULE_STATUS_INVALID,
+                               "Log level rule \"exactly\" rejected by %s event rule: level = %d",
+                               event_rule_type_str,
+                               invalid_log_level_value);
+               ok(er_as_severe_status == LTTNG_EVENT_RULE_STATUS_INVALID,
+                               "Log level rule \"as least as severe as\" rejected by %s event rule: level = %d",
+                               event_rule_type_str,
+                               invalid_log_level_value);
+       }
+
+       lttng_event_rule_destroy(rule);
+}
+
+static void test_event_rule_log_level_ust(void)
+{
+       const int tagged_log_level_values[] = {
+               LTTNG_LOGLEVEL_EMERG,
+               LTTNG_LOGLEVEL_ALERT,
+               LTTNG_LOGLEVEL_CRIT,
+               LTTNG_LOGLEVEL_ERR,
+               LTTNG_LOGLEVEL_WARNING,
+               LTTNG_LOGLEVEL_NOTICE,
+               LTTNG_LOGLEVEL_INFO,
+               LTTNG_LOGLEVEL_DEBUG_SYSTEM,
+               LTTNG_LOGLEVEL_DEBUG_PROGRAM,
+               LTTNG_LOGLEVEL_DEBUG_PROCESS,
+               LTTNG_LOGLEVEL_DEBUG_MODULE,
+               LTTNG_LOGLEVEL_DEBUG_UNIT,
+               LTTNG_LOGLEVEL_DEBUG_FUNCTION,
+               LTTNG_LOGLEVEL_DEBUG_LINE,
+               LTTNG_LOGLEVEL_DEBUG,
+       };
+       const int invalid_log_level_values[] = {
+               -1980,
+               1995,
+               LTTNG_LOGLEVEL_DEBUG + 1,
+               LTTNG_LOGLEVEL_EMERG - 1,
+       };
+
+       test_event_rule_log_level_generic(LTTNG_EVENT_RULE_TYPE_USER_TRACEPOINT,
+                       loglevel_value_to_name,
+                       lttng_event_rule_user_tracepoint_create,
+                       lttng_event_rule_user_tracepoint_set_log_level_rule,
+                       tagged_log_level_values,
+                       ARRAY_SIZE(tagged_log_level_values), NULL, 0,
+                       invalid_log_level_values,
+                       ARRAY_SIZE(invalid_log_level_values));
+}
+
+static void test_event_rule_log_level_jul(void)
+{
+       const int tagged_log_level_values[] = {
+               LTTNG_LOGLEVEL_JUL_OFF,
+               LTTNG_LOGLEVEL_JUL_SEVERE,
+               LTTNG_LOGLEVEL_JUL_WARNING,
+               LTTNG_LOGLEVEL_JUL_INFO,
+               LTTNG_LOGLEVEL_JUL_CONFIG,
+               LTTNG_LOGLEVEL_JUL_FINE,
+               LTTNG_LOGLEVEL_JUL_FINER,
+               LTTNG_LOGLEVEL_JUL_FINEST,
+               LTTNG_LOGLEVEL_JUL_ALL,
+       };
+       const int valid_log_level_values[] = {
+               0,
+               -1980,
+               1995
+       };
+
+       test_event_rule_log_level_generic(LTTNG_EVENT_RULE_TYPE_JUL_LOGGING,
+                       loglevel_jul_value_to_name,
+                       lttng_event_rule_jul_logging_create,
+                       lttng_event_rule_jul_logging_set_log_level_rule,
+                       tagged_log_level_values,
+                       ARRAY_SIZE(tagged_log_level_values),
+                       valid_log_level_values,
+                       ARRAY_SIZE(valid_log_level_values), NULL, 0);
+}
+
+static void test_event_rule_log_level_log4j(void)
+{
+       const int tagged_log_level_values[] = {
+               LTTNG_LOGLEVEL_LOG4J_OFF,
+               LTTNG_LOGLEVEL_LOG4J_FATAL,
+               LTTNG_LOGLEVEL_LOG4J_ERROR,
+               LTTNG_LOGLEVEL_LOG4J_WARN,
+               LTTNG_LOGLEVEL_LOG4J_INFO,
+               LTTNG_LOGLEVEL_LOG4J_DEBUG,
+               LTTNG_LOGLEVEL_LOG4J_TRACE,
+               LTTNG_LOGLEVEL_LOG4J_ALL,
+       };
+       const int valid_log_level_values[] = {
+               0
+               -1980,
+               1995
+       };
+
+       test_event_rule_log_level_generic(LTTNG_EVENT_RULE_TYPE_LOG4J_LOGGING,
+                       loglevel_log4j_value_to_name,
+                       lttng_event_rule_log4j_logging_create,
+                       lttng_event_rule_log4j_logging_set_log_level_rule,
+                       tagged_log_level_values,
+                       ARRAY_SIZE(tagged_log_level_values),
+                       valid_log_level_values,
+                       ARRAY_SIZE(valid_log_level_values), NULL, 0);
+}
+
+static void test_event_rule_log_level_python(void)
+{
+       const int tagged_log_level_values[] = {
+               LTTNG_LOGLEVEL_PYTHON_CRITICAL,
+               LTTNG_LOGLEVEL_PYTHON_ERROR,
+               LTTNG_LOGLEVEL_PYTHON_WARNING,
+               LTTNG_LOGLEVEL_PYTHON_INFO,
+               LTTNG_LOGLEVEL_PYTHON_DEBUG,
+               LTTNG_LOGLEVEL_PYTHON_NOTSET,
+       };
+       const int valid_log_level_values[] = {
+               45,
+               35,
+               0,
+               -657,
+       };
+
+       test_event_rule_log_level_generic(LTTNG_EVENT_RULE_TYPE_PYTHON_LOGGING,
+                       loglevel_python_value_to_name,
+                       lttng_event_rule_python_logging_create,
+                       lttng_event_rule_python_logging_set_log_level_rule,
+                       tagged_log_level_values,
+                       ARRAY_SIZE(tagged_log_level_values),
+                       valid_log_level_values,
+                       ARRAY_SIZE(valid_log_level_values),
+                       NULL, 0);
+}
+
+int main(int argc, const char *argv[])
+{
+       plan_tests(NUM_TESTS);
+       test_event_rule_kernel_tracepoint();
+       test_event_rule_user_tracepoint();
+       test_event_rule_syscall();
+       test_event_rule_userspace_probe();
+       test_event_rule_kernel_probe();
+       test_event_rule_log4j_logging();
+       test_event_rule_jul_logging();
+       test_event_rule_python_logging();
+       test_event_rule_log_level_ust();
+       test_event_rule_log_level_jul();
+       test_event_rule_log_level_log4j();
+       test_event_rule_log_level_python();
+       return exit_status();
+}
diff --git a/tests/unit/test_fd_tracker.c b/tests/unit/test_fd_tracker.c
deleted file mode 100644 (file)
index 6df179f..0000000
+++ /dev/null
@@ -1,920 +0,0 @@
-/*
- * Copyright (C) 2018 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-#include <stdlib.h>
-#include <inttypes.h>
-#include <stdbool.h>
-#include <string.h>
-#include <stdarg.h>
-#include <tap/tap.h>
-#include <sys/types.h>
-#include <dirent.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include <urcu.h>
-
-#include <common/compat/directory-handle.h>
-#include <common/compat/errno.h>
-#include <common/error.h>
-#include <common/fs-handle.h>
-#include <common/fd-tracker/fd-tracker.h>
-
-/* For error.h */
-int lttng_opt_quiet = 1;
-int lttng_opt_verbose;
-int lttng_opt_mi;
-
-/* Number of TAP tests in this file */
-#define NUM_TESTS 61
-/* 3 for stdin, stdout, and stderr */
-#define STDIO_FD_COUNT 3
-#define TRACKER_FD_LIMIT 50
-#define TMP_DIR_PATTERN "/tmp/fd-tracker-XXXXXX"
-#define TEST_UNLINK_DIRECTORY_NAME "unlinked_files"
-
-#ifdef __linux__
-#define SELF_FD_DIR "/proc/self/fd"
-#else
-/* Most Unices have /dev/fd */
-#define SELF_FD_DIR "/dev/fd"
-#endif
-
-/*
- * Count of fds, beyond stdin, stderr, stdout that were open
- * at the launch of the test. This allows the test to succeed when
- * run by automake's test runner or valgrind which both open
- * fds behind our back.
- */
-int unknown_fds_count;
-
-const char file_contents[] = "Bacon ipsum dolor amet jerky drumstick sirloin "
-       "strip steak venison boudin filet mignon picanha doner shoulder. "
-       "Strip steak brisket alcatra, venison beef chuck cupim pastrami. "
-       "Landjaeger tri-tip salami leberkas ball tip, ham hock chuck sausage "
-       "flank jerky cupim. Pig bacon chuck pancetta andouille.";
-
-static
-void get_temporary_directories(char **_test_directory, char **_unlink_directory)
-{
-       int ret;
-       char tmp_path_pattern[] = TMP_DIR_PATTERN;
-       char *output_dir;
-
-       output_dir = mkdtemp(tmp_path_pattern);
-       if (!output_dir) {
-               diag("Failed to create temporary path of the form %s",
-                               TMP_DIR_PATTERN);
-               abort();
-       }
-
-       *_test_directory = strdup(output_dir);
-       LTTNG_ASSERT(*_test_directory);
-       ret = asprintf(_unlink_directory, "%s/%s", output_dir,
-                       TEST_UNLINK_DIRECTORY_NAME);
-       if (ret < 0) {
-               abort();
-       }
-}
-
-static
-int fd_count(void)
-{
-       DIR *dir;
-       struct dirent *entry;
-       int count = 0;
-
-       dir = opendir(SELF_FD_DIR);
-       if (!dir) {
-               perror("# Failed to enumerate " SELF_FD_DIR " to count the number of used file descriptors");
-               count = -1;
-               goto end;
-       }
-
-       while ((entry = readdir(dir)) != NULL) {
-               if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) {
-                       continue;
-               }
-               count++;
-       }
-       /* Don't account for the file descriptor opened by opendir(). */
-       count--;
-       if (closedir(dir)) {
-               perror("# Failed to close test program's " SELF_FD_DIR " directory file descriptor");
-       }
-end:
-       return count;
-}
-
-static
-void check_fd_count(int expected_count)
-{
-       int count = 0;
-
-       count = fd_count();
-       ok(count == expected_count, "Expected %d open file descriptors (%d are open)",
-                       expected_count, count);
-}
-
-static
-int noop_open(void *data, int *fds)
-{
-       *fds = *((int *) data);
-       return 0;
-}
-
-static
-int noop_close(void *data, int *fds)
-{
-       return 0;
-}
-
-static
-void track_std_fds(struct fd_tracker *tracker)
-{
-       int i;
-       struct { int fd; const char *name; } files[] = {
-               { .fd = fileno(stdin), .name = "stdin" },
-               { .fd = fileno(stdout), .name = "stdout" },
-               { .fd = fileno(stderr), .name = "stderr" },
-       };
-
-       for (i = 0; i < sizeof(files) / sizeof(*files); i++) {
-               int out_fd, ret;
-
-               ret = fd_tracker_open_unsuspendable_fd(tracker, &out_fd,
-                               &files[i].name, 1, noop_open, &files[i].fd);
-               LTTNG_ASSERT(out_fd == files[i].fd);
-
-               ok(ret == 0, "Track unsuspendable fd %d (%s)", files[i].fd,
-                               files[i].name);
-       }
-}
-
-static
-void untrack_std_fds(struct fd_tracker *tracker)
-{
-       int i;
-       struct { int fd; const char *name; } files[] = {
-               { .fd = fileno(stdin), .name = "stdin" },
-               { .fd = fileno(stdout), .name = "stdout" },
-               { .fd = fileno(stderr), .name = "stderr" },
-       };
-
-       for (i = 0; i < sizeof(files) / sizeof(*files); i++) {
-               int fd = files[i].fd;
-               int ret = fd_tracker_close_unsuspendable_fd(tracker,
-                               &files[i].fd, 1, noop_close, NULL);
-
-               ok(ret == 0, "Untrack unsuspendable fd %d (%s)", fd,
-                               files[i].name);
-       }
-}
-
-/*
- * Basic test opening and closing three unsuspendable fds. 
- */
-static
-void test_unsuspendable_basic(void)
-{
-       int ret;
-       struct fd_tracker *tracker;
-       char *test_directory = NULL, *unlinked_files_directory = NULL;
-
-       get_temporary_directories(&test_directory, &unlinked_files_directory);
-
-       tracker = fd_tracker_create(unlinked_files_directory, TRACKER_FD_LIMIT);
-       ok(tracker, "Created an fd tracker with a limit of %d simulateously opened file descriptors",
-                       TRACKER_FD_LIMIT);
-       if (!tracker) {
-               goto end;
-       }
-
-       track_std_fds(tracker);
-       untrack_std_fds(tracker);
-
-       fd_tracker_destroy(tracker);
-       ret = rmdir(test_directory);
-       ok(ret == 0, "Test directory is empty");
-end:
-       free(test_directory);
-       free(unlinked_files_directory);
-}
-
-static
-int error_open(void *data, int *fds)
-{
-       return *((int *) data);
-}
-
-static
-int error_close(void *data, int *fds)
-{
-       return *((int *) data);
-}
-
-/*
- * Validate that user callback return values are returned to the
- * caller of the fd tracker.
- */
-static
-void test_unsuspendable_cb_return(void)
-{
-       int ret, stdout_fd = fileno(stdout), out_fd = 42;
-       struct fd_tracker *tracker;
-       int expected_error = -ENETDOWN;
-       char *test_directory = NULL, *unlinked_files_directory = NULL;
-
-       get_temporary_directories(&test_directory, &unlinked_files_directory);
-
-       tracker = fd_tracker_create(test_directory, TRACKER_FD_LIMIT);
-       LTTNG_ASSERT(tracker);
-
-       /* The error_open callback should fail and return 'expected_error'. */
-       ret = fd_tracker_open_unsuspendable_fd(tracker, &out_fd,
-                       NULL, 1, error_open, &expected_error);
-       ok(ret == expected_error, "fd_tracker_open_unsuspendable_fd() forwards the user callback's error code");
-       ok(out_fd == 42, "Output fd parameter is unaffected on error of fd_tracker_open_unsuspendable_fd()");
-
-       /*
-        * Track a valid fd since we don't want the tracker to fail with an
-        * invalid fd error for this test.
-        */
-       ret = fd_tracker_open_unsuspendable_fd(tracker, &out_fd,
-                       NULL, 1, noop_open, &stdout_fd);
-       ok(out_fd == stdout_fd, "fd_tracker_open_unsuspendable_fd() sets the output fd parameter to the newly-tracked fd's value");
-       LTTNG_ASSERT(!ret);
-
-       ret = fd_tracker_close_unsuspendable_fd(tracker,
-                       &stdout_fd, 1, error_close, &expected_error);
-       ok(ret == expected_error, "fd_tracker_close_unsuspendable_fd() forwards the user callback's error code");
-       ret = fd_tracker_close_unsuspendable_fd(tracker,
-                       &stdout_fd, 1, noop_close, &expected_error);
-       LTTNG_ASSERT(!ret);
-
-       fd_tracker_destroy(tracker);
-       ret = rmdir(test_directory);
-       ok(ret == 0, "Test directory is empty");
-       free(test_directory);
-       free(unlinked_files_directory);
-}
-
-/*
- * Validate that the tracker refuses to track two identical unsuspendable
- * file descriptors.
- */
-static
-void test_unsuspendable_duplicate(void)
-{
-       int ret, stdout_fd = fileno(stdout), out_fd;
-       struct fd_tracker *tracker;
-       char *test_directory = NULL, *unlinked_files_directory = NULL;
-
-       get_temporary_directories(&test_directory, &unlinked_files_directory);
-
-       tracker = fd_tracker_create(unlinked_files_directory, TRACKER_FD_LIMIT);
-       LTTNG_ASSERT(tracker);
-
-       ret = fd_tracker_open_unsuspendable_fd(tracker, &out_fd,
-                       NULL, 1, noop_open, &stdout_fd);
-       LTTNG_ASSERT(!ret);
-       ret = fd_tracker_open_unsuspendable_fd(tracker, &out_fd,
-                       NULL, 1, noop_open, &stdout_fd);
-       ok(ret == -EEXIST, "EEXIST reported on open of an already tracked file descriptor");
-
-       ret = fd_tracker_close_unsuspendable_fd(tracker,
-                       &stdout_fd, 1, noop_close, NULL);
-       LTTNG_ASSERT(!ret);
-
-       fd_tracker_destroy(tracker);
-       ret = rmdir(test_directory);
-       ok(ret == 0, "Test directory is empty");
-       free(test_directory);
-       free(unlinked_files_directory);
-}
-
-static
-int open_pipes(void *data, int *out_fds)
-{
-       unsigned int i;
-       const unsigned int pipe_count = TRACKER_FD_LIMIT / 2;
-
-       for (i = 0; i < pipe_count; i++) {
-               int ret = pipe(&out_fds[i * 2]);
-
-               if (ret) {
-                       return -errno;
-               }
-       }
-       return 0;
-}
-
-static
-int close_pipes(void *data, int *fds)
-{
-       int i;
-       int *pipes = fds;
-
-       for (i = 0; i < TRACKER_FD_LIMIT; i++) {
-               int ret = close(pipes[i]);
-
-               if (ret) {
-                       return -errno;
-               }
-       }
-       return 0;
-}
-
-/*
- * Validate that the tracker enforces the open file descriptor limit
- * when unsuspendable file descriptors are being opened.
- */
-static
-void test_unsuspendable_limit(void)
-{
-       struct fd_tracker *tracker;
-       int ret, stdout_fd = fileno(stdout), out_fd;
-       int fds[TRACKER_FD_LIMIT];
-       char *test_directory = NULL, *unlinked_files_directory = NULL;
-
-       get_temporary_directories(&test_directory, &unlinked_files_directory);
-
-       /* This test assumes TRACKER_FD_LIMIT is a multiple of 2. */
-       LTTNG_ASSERT((TRACKER_FD_LIMIT % 2 == 0) && TRACKER_FD_LIMIT);
-
-       tracker = fd_tracker_create(unlinked_files_directory, TRACKER_FD_LIMIT);
-       LTTNG_ASSERT(tracker);
-
-       ret = fd_tracker_open_unsuspendable_fd(tracker, fds,
-                       NULL, TRACKER_FD_LIMIT, open_pipes, NULL);
-       ok(ret == 0, "File descriptor tracker allowed the user to meet its limit with unsuspendable file descriptors (%d)",
-                       TRACKER_FD_LIMIT);
-
-       ret = fd_tracker_open_unsuspendable_fd(tracker, &out_fd,
-                       NULL, 1, noop_open, &stdout_fd);
-       ok(ret == -EMFILE, "EMFILE reported when exceeding the file descriptor limit while opening an unsuspendable fd");
-
-       ret = fd_tracker_close_unsuspendable_fd(tracker,
-                       fds, TRACKER_FD_LIMIT, close_pipes, NULL);
-       LTTNG_ASSERT(!ret);
-
-       fd_tracker_destroy(tracker);
-       ret = rmdir(test_directory);
-       ok(ret == 0, "Test directory is empty");
-       free(test_directory);
-       free(unlinked_files_directory);
-}
-
-/*
- * Validate that the tracker refuses to track two identical unsuspendable
- * file descriptors.
- */
-static
-void test_unsuspendable_close_untracked(void)
-{
-       int ret, stdout_fd = fileno(stdout), unknown_fds[2], out_fd;
-       struct fd_tracker *tracker;
-       char *test_directory = NULL, *unlinked_files_directory = NULL;
-
-       get_temporary_directories(&test_directory, &unlinked_files_directory);
-
-       tracker = fd_tracker_create(unlinked_files_directory, TRACKER_FD_LIMIT);
-       if (!tracker) {
-               goto end;;
-       }
-
-       ret = pipe(unknown_fds);
-       LTTNG_ASSERT(!ret);
-       ret = close(unknown_fds[0]);
-       LTTNG_ASSERT(ret == 0);
-       ret = close(unknown_fds[1]);
-       LTTNG_ASSERT(ret == 0);
-
-       ret = fd_tracker_open_unsuspendable_fd(tracker, &out_fd,
-                       NULL, 1, noop_open, &stdout_fd);
-       LTTNG_ASSERT(!ret);
-
-       ret = fd_tracker_close_unsuspendable_fd(tracker,
-                       unknown_fds, 1, noop_close, NULL);
-       ok(ret == -EINVAL, "EINVAL reported on close of an untracked file descriptor");
-
-       ret = fd_tracker_close_unsuspendable_fd(tracker,
-                       &stdout_fd, 1, noop_close, NULL);
-       LTTNG_ASSERT(!ret);
-
-       fd_tracker_destroy(tracker);
-       ret = rmdir(test_directory);
-       ok(ret == 0, "Test directory is empty");
-end:
-       free(test_directory);
-       free(unlinked_files_directory);
-}
-
-static int open_files(struct fd_tracker *tracker,
-               struct lttng_directory_handle *directory,
-               unsigned int count,
-               struct fs_handle **handles,
-               char **file_paths)
-{
-       int ret = 0;
-       unsigned int i;
-
-       for (i = 0; i < count; i++) {
-               int p_ret;
-               char *file_path;
-               struct fs_handle *handle;
-               mode_t mode = S_IWUSR | S_IRUSR;
-
-               p_ret = asprintf(&file_path, "file-%u", i);
-               LTTNG_ASSERT(p_ret >= 0);
-               file_paths[i] = file_path;
-
-               handle = fd_tracker_open_fs_handle(tracker, directory, file_path,
-                               O_RDWR | O_CREAT, &mode);
-               if (!handle) {
-                       ret = -1;
-                       break;
-               }
-               handles[i] = handle;
-       }
-       return ret;
-}
-
-static int open_same_file(struct fd_tracker *tracker,
-               struct lttng_directory_handle *directory,
-               const char *file,
-               unsigned int count,
-               struct fs_handle **handles)
-{
-       int ret = 0;
-       unsigned int i;
-
-       for (i = 0; i < count; i++) {
-               struct fs_handle *handle;
-               mode_t mode = S_IWUSR | S_IRUSR;
-
-               handle = fd_tracker_open_fs_handle(tracker, directory, file,
-                               O_RDWR | O_CREAT, &mode);
-               if (!handle) {
-                       ret = -1;
-                       break;
-               }
-               handles[i] = handle;
-       }
-       return ret;
-}
-
-static
-int cleanup_files(struct fd_tracker *tracker, const char *dir,
-               unsigned int count, struct fs_handle **handles,
-               char **file_paths)
-{
-       int ret = 0;
-       unsigned int i;
-
-       for (i = 0; i < count; i++) {
-               char *file_path = file_paths[i];
-
-               if (!file_path) {
-                       break;
-               }
-               if (fs_handle_unlink(handles[i])) {
-                       diag("Failed to unlink fs_handle to file %s", file_path);
-                       ret = -1;
-               }
-               if (fs_handle_close(handles[i])) {
-                       diag("Failed to close fs_handle to file %s", file_path);
-                       ret = -1;
-               }
-               free(file_path);
-       }
-       return ret;
-}
-
-static
-void test_suspendable_limit(void)
-{
-       int ret;
-       const int files_to_create = TRACKER_FD_LIMIT * 10;
-       struct fd_tracker *tracker;
-       char *test_directory = NULL, *unlinked_files_directory = NULL;
-       char *output_files[files_to_create];
-       struct fs_handle *handles[files_to_create];
-       struct lttng_directory_handle *dir_handle = NULL;
-       int dir_handle_fd_count;
-
-       memset(output_files, 0, sizeof(output_files));
-       memset(handles, 0, sizeof(handles));
-
-       get_temporary_directories(&test_directory, &unlinked_files_directory);
-
-       tracker = fd_tracker_create(unlinked_files_directory, TRACKER_FD_LIMIT);
-       if (!tracker) {
-               goto end;
-       }
-
-       dir_handle = lttng_directory_handle_create(test_directory);
-       LTTNG_ASSERT(dir_handle);
-       dir_handle_fd_count = !!lttng_directory_handle_uses_fd(dir_handle);
-
-       ret = open_files(tracker, dir_handle, files_to_create, handles,
-                       output_files);
-       ok(!ret, "Created %d files with a limit of %d simultaneously-opened file descriptor",
-                       files_to_create, TRACKER_FD_LIMIT);
-       check_fd_count(TRACKER_FD_LIMIT + STDIO_FD_COUNT + unknown_fds_count +
-                       dir_handle_fd_count);
-
-       ret = cleanup_files(tracker, test_directory, files_to_create, handles,
-                       output_files);
-       ok(!ret, "Close all opened filesystem handles");
-       ret = rmdir(test_directory);
-       ok(ret == 0, "Test directory is empty");
-       fd_tracker_destroy(tracker);
-       lttng_directory_handle_put(dir_handle);
-end:
-       free(test_directory);
-       free(unlinked_files_directory);
-}
-
-static
-void test_mixed_limit(void)
-{
-       int ret;
-       const int files_to_create = TRACKER_FD_LIMIT;
-       struct fd_tracker *tracker;
-       char *test_directory = NULL, *unlinked_files_directory = NULL;
-       char *output_files[files_to_create];
-       struct fs_handle *handles[files_to_create];
-       struct lttng_directory_handle *dir_handle = NULL;
-       int dir_handle_fd_count;
-
-       memset(output_files, 0, sizeof(output_files));
-       memset(handles, 0, sizeof(handles));
-
-       get_temporary_directories(&test_directory, &unlinked_files_directory);
-
-       tracker = fd_tracker_create(unlinked_files_directory, TRACKER_FD_LIMIT);
-       if (!tracker) {
-               goto end;
-       }
-
-       dir_handle = lttng_directory_handle_create(test_directory);
-       LTTNG_ASSERT(dir_handle);
-       dir_handle_fd_count = !!lttng_directory_handle_uses_fd(dir_handle);
-
-       ret = open_files(tracker, dir_handle, files_to_create, handles,
-                       output_files);
-       ok(!ret, "Created %d files with a limit of %d simultaneously-opened file descriptor",
-                       files_to_create, TRACKER_FD_LIMIT);
-       diag("Check file descriptor count after opening %u files", files_to_create);
-       check_fd_count(TRACKER_FD_LIMIT + STDIO_FD_COUNT + unknown_fds_count +
-                       dir_handle_fd_count);
-
-       /*
-        * Open unsuspendable fds (stdin, stdout, stderr) and verify that the fd
-        * cap is still respected.
-        */
-       diag("Check file descriptor count after adding %d unsuspendable fds",
-                       STDIO_FD_COUNT);
-       track_std_fds(tracker);
-       check_fd_count(TRACKER_FD_LIMIT + unknown_fds_count +
-                       dir_handle_fd_count);
-       diag("Untrack unsuspendable file descriptors");
-       untrack_std_fds(tracker);
-       check_fd_count(TRACKER_FD_LIMIT + unknown_fds_count +
-                       dir_handle_fd_count);
-
-       ret = cleanup_files(tracker, test_directory, files_to_create, handles,
-                       output_files);
-       ok(!ret, "Close all opened filesystem handles");
-       ret = rmdir(test_directory);
-       ok(ret == 0, "Test directory is empty");
-       fd_tracker_destroy(tracker);
-       lttng_directory_handle_put(dir_handle);
-end:
-       free(test_directory);
-       free(unlinked_files_directory);
-}
-
-/*
- * Open more files than allowed by the fd tracker's cap and write,
- * byte-by-byte, and in round-robin, a string. The goal is to force
- * the fd tracker to suspend and resume the fs_handles often and
- * verify that the fd cap is always respected.
- *
- * The content of the files is also verified at the end.
- */
-static
-void test_suspendable_restore(void)
-{
-       int ret;
-       const int files_to_create = TRACKER_FD_LIMIT * 10;
-       struct fd_tracker *tracker;
-       char *output_files[files_to_create];
-       struct fs_handle *handles[files_to_create];
-       size_t content_index;
-       int handle_index;
-       bool write_success = true;
-       bool fd_cap_respected = true;
-       bool content_ok = true;
-       struct lttng_directory_handle *dir_handle = NULL;
-       int dir_handle_fd_count;
-       char *test_directory = NULL, *unlinked_files_directory = NULL;
-
-       memset(output_files, 0, sizeof(output_files));
-       memset(handles, 0, sizeof(handles));
-
-       get_temporary_directories(&test_directory, &unlinked_files_directory);
-
-       tracker = fd_tracker_create(unlinked_files_directory, TRACKER_FD_LIMIT);
-       if (!tracker) {
-               goto end;
-       }
-
-       dir_handle = lttng_directory_handle_create(test_directory);
-       LTTNG_ASSERT(dir_handle);
-       dir_handle_fd_count = !!lttng_directory_handle_uses_fd(dir_handle);
-
-       ret = open_files(tracker, dir_handle, files_to_create, handles,
-                       output_files);
-       ok(!ret, "Created %d files with a limit of %d simultaneously-opened file descriptor",
-                       files_to_create, TRACKER_FD_LIMIT);
-       diag("Check file descriptor count after opening %u files", files_to_create);
-       check_fd_count(TRACKER_FD_LIMIT + STDIO_FD_COUNT + unknown_fds_count +
-                       dir_handle_fd_count);
-
-       for (content_index = 0; content_index < sizeof(file_contents); content_index++) {
-               for (handle_index = 0; handle_index < files_to_create; handle_index++) {
-                       int fd;
-                       struct fs_handle *handle = handles[handle_index];
-                       const char *path = output_files[handle_index];
-
-                       fd = fs_handle_get_fd(handle);
-                       if (fd < 0) {
-                               write_success = false;
-                               diag("Failed to restore fs_handle to %s",
-                                               path);
-                               goto skip_write;
-                       }
-
-                       do {
-                               ret = write(fd, file_contents + content_index, 1);
-                       } while (ret < 0 && errno == EINTR);
-
-                       if (ret != 1) {
-                               write_success = false;
-                               PERROR("write() to %s failed", path);
-                               goto skip_write;
-                       }
-
-                       if (fd_count() > (TRACKER_FD_LIMIT + STDIO_FD_COUNT +
-                                                       unknown_fds_count +
-                                                       dir_handle_fd_count)) {
-                               fd_cap_respected = false;
-                       }
-
-                       fs_handle_put_fd(handle);
-               }
-       }
-skip_write:
-       ok(write_success, "Wrote reference string to %d files",
-                       files_to_create);
-       ok(fd_cap_respected, "FD tracker enforced the file descriptor cap");
-
-       /* Validate the contents of the files. */
-       for (handle_index = 0; handle_index < files_to_create; handle_index++) {
-               struct stat fd_stat;
-               const char *path = output_files[handle_index];
-               char read_buf[sizeof(file_contents)];
-               char *read_pos;
-               size_t to_read = sizeof(read_buf);
-               int fd;
-
-               fd = lttng_directory_handle_open_file(
-                               dir_handle, path, O_RDONLY, 0);
-               LTTNG_ASSERT(fd >= 0);
-               ret = fstat(fd, &fd_stat);
-               LTTNG_ASSERT(!ret);
-               if (fd_stat.st_size != sizeof(file_contents)) {
-                       diag("Content size of file %s doesn't match, got %" PRId64 ", expected %zu",
-                                       path, (int64_t) fd_stat.st_size,
-                                       sizeof(file_contents));
-                       content_ok = false;
-                       (void) close(fd);
-                       break;
-               }
-
-               read_pos = read_buf;
-               do {
-                       ret = read(fd, read_pos, to_read);
-                       if (ret > 0) {
-                               to_read -= ret;
-                               read_pos += ret;
-                       }
-               } while (to_read && (ret < 0 && errno == EINTR));
-               if (ret < 0) {
-                       content_ok = false;
-                       PERROR("Failed to read file %s", path);
-                       (void) close(fd);
-                       break;
-               }
-
-               if (strcmp(file_contents, read_buf)) {
-                       content_ok = false;
-                       diag("File content doesn't match the expectated string");
-                       (void) close(fd);
-                       break;
-               }
-               (void) close(fd);
-       }
-       ok(content_ok, "Files contain the expected content");
-       ret = cleanup_files(tracker, test_directory, files_to_create, handles,
-                       output_files);
-       ok(!ret, "Close all opened filesystem handles");
-       ret = rmdir(test_directory);
-       ok(ret == 0, "Test directory is empty");
-       fd_tracker_destroy(tracker);
-       lttng_directory_handle_put(dir_handle);
-end:
-       free(test_directory);
-       free(unlinked_files_directory);
-}
-
-static
-void test_unlink(void)
-{
-       int ret;
-       struct fd_tracker *tracker;
-       const int handles_to_open = 2;
-       struct fs_handle *handles[handles_to_open];
-       struct fs_handle *new_handle = NULL;
-       struct stat statbuf;
-       struct lttng_directory_handle *dir_handle = NULL;
-       const char file_name[] = "my_file";
-       char *test_directory = NULL, *unlinked_files_directory = NULL;
-       char *unlinked_file_zero = NULL, *unlinked_file_one = NULL;
-       int fd;
-
-       get_temporary_directories(&test_directory, &unlinked_files_directory);
-       ret = asprintf(&unlinked_file_zero, "%s/%u", unlinked_files_directory,
-                       0);
-       LTTNG_ASSERT(ret > 0);
-       ret = asprintf(&unlinked_file_one, "%s/%u", unlinked_files_directory,
-                       1);
-       LTTNG_ASSERT(ret > 0);
-
-       tracker = fd_tracker_create(unlinked_files_directory, 1);
-       if (!tracker) {
-               goto end;
-       }
-
-       dir_handle = lttng_directory_handle_create(test_directory);
-       LTTNG_ASSERT(dir_handle);
-
-       /* Open two handles to the same file. */
-       ret = open_same_file(tracker, dir_handle, file_name, handles_to_open,
-                       handles);
-       ok(!ret, "Successfully opened %i handles to %s/%s", handles_to_open,
-                       test_directory, file_name);
-       if (ret) {
-               goto end;
-       }
-
-       /*
-        * Unlinking the first handle should cause the file to be renamed
-        * to '0'.
-        */
-       ret = fs_handle_unlink(handles[0]);
-       ok(!ret, "Successfully unlinked the first handle to %s/%s",
-                       test_directory, file_name);
-
-       /*
-        * The original file should no longer exist on the file system, and a
-        * new file named '0' should exist.
-        */
-       ok(lttng_directory_handle_stat(dir_handle, file_name, &statbuf) == -1 &&
-                                       errno == ENOENT,
-                       "%s no longer present on file system after unlink",
-                       file_name);
-       ok(lttng_directory_handle_stat(
-                       dir_handle, unlinked_file_zero, &statbuf) == 0,
-                       "%s exists on file system after unlink",
-                       unlinked_file_zero);
-
-       /*
-        * It should be possible to use the file descriptors of both handles.
-        * Since only one file descriptor can be opened at once, this should
-        * force the fd_tracker to suspend and restore the handles.
-        */
-       fd = fs_handle_get_fd(handles[0]);
-       ok(fd >= 0, "Got fd from first handle");
-
-       fd = fs_handle_get_fd(handles[1]);
-       ok (fd < 0, "fd tracker does not allow two fds to be used at once");
-
-       fs_handle_put_fd(handles[0]);
-       fd = fs_handle_get_fd(handles[1]);
-       ok(fd >= 0, "Got fd from second handle");
-       fs_handle_put_fd(handles[1]);
-
-       /* The second unlink should fail with -ENOENT. */
-       ret = fs_handle_unlink(handles[1]);
-       ok(ret == -ENOENT,
-                       "ENOENT is reported when attempting to unlink the second handle to %s/%s",
-                       test_directory, file_name);
-
-       /*
-        * Opening a new handle to 'my_file' should succeed.
-        */
-       ret = open_same_file(tracker, dir_handle, file_name, 1, &new_handle);
-       ok(!ret, "Successfully opened a new handle to previously unlinked file %s/%s",
-                       test_directory, file_name);
-       LTTNG_ASSERT(new_handle);
-
-       /*
-        * Unlinking the new handle should cause the file to be renamed
-        * to '1' since '0' already exists.
-        */
-       ret = fs_handle_unlink(new_handle);
-       ok(!ret, "Successfully unlinked the new handle handle to %s/%s",
-                       test_directory, file_name);
-       ok(stat(unlinked_file_one, &statbuf) == 0,
-                       "%s exists on file system after unlink",
-                       unlinked_file_one);
-
-       ret = fs_handle_close(handles[0]);
-       ok(!ret, "Successfully closed the first handle");
-       ret = fs_handle_close(handles[1]);
-       ok(!ret, "Successfully closed the second handle");
-       ret = fs_handle_close(new_handle);
-       ok(!ret, "Successfully closed the third handle");
-
-       ok(lttng_directory_handle_stat(dir_handle, file_name, &statbuf) == -1 &&
-                                       errno == ENOENT,
-                       "%s no longer present on file system after handle close",
-                       file_name);
-       ok(lttng_directory_handle_stat(
-                       dir_handle, unlinked_file_zero, &statbuf) == -1 &&
-                                       errno == ENOENT,
-                       "%s no longer present on file system after handle close",
-                       unlinked_file_zero);
-       ok(lttng_directory_handle_stat(dir_handle, unlinked_file_one,
-                       &statbuf) == -1 &&
-                                       errno == ENOENT,
-                       "%s no longer present on file system after handle close",
-                       unlinked_file_one);
-
-       ret = rmdir(test_directory);
-       ok(ret == 0, "Test directory is empty");
-end:
-       fd_tracker_destroy(tracker);
-       free(test_directory);
-       free(unlinked_files_directory);
-       free(unlinked_file_zero);
-       free(unlinked_file_one);
-       lttng_directory_handle_put(dir_handle);
-}
-
-int main(int argc, char **argv)
-{
-       plan_tests(NUM_TESTS);
-       diag("File descriptor tracker unit tests");
-
-       rcu_register_thread();
-
-       unknown_fds_count = fd_count() - STDIO_FD_COUNT;
-       LTTNG_ASSERT(unknown_fds_count >= 0);
-
-       diag("Unsuspendable - basic");
-       test_unsuspendable_basic();
-       diag("Unsuspendable - callback return values");
-       test_unsuspendable_cb_return();
-       diag("Unsuspendable - duplicate file descriptors");
-       test_unsuspendable_duplicate();
-       diag("Unsuspendable - closing an untracked file descriptor");
-       test_unsuspendable_close_untracked();
-       diag("Unsuspendable - check that file descriptor limit is enforced");
-       test_unsuspendable_limit();
-
-       diag("Suspendable - check that file descriptor limit is enforced");
-       test_suspendable_limit();
-       diag("Suspendable - restoration test");
-       test_suspendable_restore();
-
-       diag("Mixed - check that file descriptor limit is enforced");
-       test_mixed_limit();
-
-       diag("Suspendable - Unlinking test");
-       test_unlink();
-
-       rcu_barrier();
-       rcu_unregister_thread();
-       return exit_status();
-}
diff --git a/tests/unit/test_fd_tracker.cpp b/tests/unit/test_fd_tracker.cpp
new file mode 100644 (file)
index 0000000..6df179f
--- /dev/null
@@ -0,0 +1,920 @@
+/*
+ * Copyright (C) 2018 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <string.h>
+#include <stdarg.h>
+#include <tap/tap.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <urcu.h>
+
+#include <common/compat/directory-handle.h>
+#include <common/compat/errno.h>
+#include <common/error.h>
+#include <common/fs-handle.h>
+#include <common/fd-tracker/fd-tracker.h>
+
+/* For error.h */
+int lttng_opt_quiet = 1;
+int lttng_opt_verbose;
+int lttng_opt_mi;
+
+/* Number of TAP tests in this file */
+#define NUM_TESTS 61
+/* 3 for stdin, stdout, and stderr */
+#define STDIO_FD_COUNT 3
+#define TRACKER_FD_LIMIT 50
+#define TMP_DIR_PATTERN "/tmp/fd-tracker-XXXXXX"
+#define TEST_UNLINK_DIRECTORY_NAME "unlinked_files"
+
+#ifdef __linux__
+#define SELF_FD_DIR "/proc/self/fd"
+#else
+/* Most Unices have /dev/fd */
+#define SELF_FD_DIR "/dev/fd"
+#endif
+
+/*
+ * Count of fds, beyond stdin, stderr, stdout that were open
+ * at the launch of the test. This allows the test to succeed when
+ * run by automake's test runner or valgrind which both open
+ * fds behind our back.
+ */
+int unknown_fds_count;
+
+const char file_contents[] = "Bacon ipsum dolor amet jerky drumstick sirloin "
+       "strip steak venison boudin filet mignon picanha doner shoulder. "
+       "Strip steak brisket alcatra, venison beef chuck cupim pastrami. "
+       "Landjaeger tri-tip salami leberkas ball tip, ham hock chuck sausage "
+       "flank jerky cupim. Pig bacon chuck pancetta andouille.";
+
+static
+void get_temporary_directories(char **_test_directory, char **_unlink_directory)
+{
+       int ret;
+       char tmp_path_pattern[] = TMP_DIR_PATTERN;
+       char *output_dir;
+
+       output_dir = mkdtemp(tmp_path_pattern);
+       if (!output_dir) {
+               diag("Failed to create temporary path of the form %s",
+                               TMP_DIR_PATTERN);
+               abort();
+       }
+
+       *_test_directory = strdup(output_dir);
+       LTTNG_ASSERT(*_test_directory);
+       ret = asprintf(_unlink_directory, "%s/%s", output_dir,
+                       TEST_UNLINK_DIRECTORY_NAME);
+       if (ret < 0) {
+               abort();
+       }
+}
+
+static
+int fd_count(void)
+{
+       DIR *dir;
+       struct dirent *entry;
+       int count = 0;
+
+       dir = opendir(SELF_FD_DIR);
+       if (!dir) {
+               perror("# Failed to enumerate " SELF_FD_DIR " to count the number of used file descriptors");
+               count = -1;
+               goto end;
+       }
+
+       while ((entry = readdir(dir)) != NULL) {
+               if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) {
+                       continue;
+               }
+               count++;
+       }
+       /* Don't account for the file descriptor opened by opendir(). */
+       count--;
+       if (closedir(dir)) {
+               perror("# Failed to close test program's " SELF_FD_DIR " directory file descriptor");
+       }
+end:
+       return count;
+}
+
+static
+void check_fd_count(int expected_count)
+{
+       int count = 0;
+
+       count = fd_count();
+       ok(count == expected_count, "Expected %d open file descriptors (%d are open)",
+                       expected_count, count);
+}
+
+static
+int noop_open(void *data, int *fds)
+{
+       *fds = *((int *) data);
+       return 0;
+}
+
+static
+int noop_close(void *data, int *fds)
+{
+       return 0;
+}
+
+static
+void track_std_fds(struct fd_tracker *tracker)
+{
+       int i;
+       struct { int fd; const char *name; } files[] = {
+               { .fd = fileno(stdin), .name = "stdin" },
+               { .fd = fileno(stdout), .name = "stdout" },
+               { .fd = fileno(stderr), .name = "stderr" },
+       };
+
+       for (i = 0; i < sizeof(files) / sizeof(*files); i++) {
+               int out_fd, ret;
+
+               ret = fd_tracker_open_unsuspendable_fd(tracker, &out_fd,
+                               &files[i].name, 1, noop_open, &files[i].fd);
+               LTTNG_ASSERT(out_fd == files[i].fd);
+
+               ok(ret == 0, "Track unsuspendable fd %d (%s)", files[i].fd,
+                               files[i].name);
+       }
+}
+
+static
+void untrack_std_fds(struct fd_tracker *tracker)
+{
+       int i;
+       struct { int fd; const char *name; } files[] = {
+               { .fd = fileno(stdin), .name = "stdin" },
+               { .fd = fileno(stdout), .name = "stdout" },
+               { .fd = fileno(stderr), .name = "stderr" },
+       };
+
+       for (i = 0; i < sizeof(files) / sizeof(*files); i++) {
+               int fd = files[i].fd;
+               int ret = fd_tracker_close_unsuspendable_fd(tracker,
+                               &files[i].fd, 1, noop_close, NULL);
+
+               ok(ret == 0, "Untrack unsuspendable fd %d (%s)", fd,
+                               files[i].name);
+       }
+}
+
+/*
+ * Basic test opening and closing three unsuspendable fds. 
+ */
+static
+void test_unsuspendable_basic(void)
+{
+       int ret;
+       struct fd_tracker *tracker;
+       char *test_directory = NULL, *unlinked_files_directory = NULL;
+
+       get_temporary_directories(&test_directory, &unlinked_files_directory);
+
+       tracker = fd_tracker_create(unlinked_files_directory, TRACKER_FD_LIMIT);
+       ok(tracker, "Created an fd tracker with a limit of %d simulateously opened file descriptors",
+                       TRACKER_FD_LIMIT);
+       if (!tracker) {
+               goto end;
+       }
+
+       track_std_fds(tracker);
+       untrack_std_fds(tracker);
+
+       fd_tracker_destroy(tracker);
+       ret = rmdir(test_directory);
+       ok(ret == 0, "Test directory is empty");
+end:
+       free(test_directory);
+       free(unlinked_files_directory);
+}
+
+static
+int error_open(void *data, int *fds)
+{
+       return *((int *) data);
+}
+
+static
+int error_close(void *data, int *fds)
+{
+       return *((int *) data);
+}
+
+/*
+ * Validate that user callback return values are returned to the
+ * caller of the fd tracker.
+ */
+static
+void test_unsuspendable_cb_return(void)
+{
+       int ret, stdout_fd = fileno(stdout), out_fd = 42;
+       struct fd_tracker *tracker;
+       int expected_error = -ENETDOWN;
+       char *test_directory = NULL, *unlinked_files_directory = NULL;
+
+       get_temporary_directories(&test_directory, &unlinked_files_directory);
+
+       tracker = fd_tracker_create(test_directory, TRACKER_FD_LIMIT);
+       LTTNG_ASSERT(tracker);
+
+       /* The error_open callback should fail and return 'expected_error'. */
+       ret = fd_tracker_open_unsuspendable_fd(tracker, &out_fd,
+                       NULL, 1, error_open, &expected_error);
+       ok(ret == expected_error, "fd_tracker_open_unsuspendable_fd() forwards the user callback's error code");
+       ok(out_fd == 42, "Output fd parameter is unaffected on error of fd_tracker_open_unsuspendable_fd()");
+
+       /*
+        * Track a valid fd since we don't want the tracker to fail with an
+        * invalid fd error for this test.
+        */
+       ret = fd_tracker_open_unsuspendable_fd(tracker, &out_fd,
+                       NULL, 1, noop_open, &stdout_fd);
+       ok(out_fd == stdout_fd, "fd_tracker_open_unsuspendable_fd() sets the output fd parameter to the newly-tracked fd's value");
+       LTTNG_ASSERT(!ret);
+
+       ret = fd_tracker_close_unsuspendable_fd(tracker,
+                       &stdout_fd, 1, error_close, &expected_error);
+       ok(ret == expected_error, "fd_tracker_close_unsuspendable_fd() forwards the user callback's error code");
+       ret = fd_tracker_close_unsuspendable_fd(tracker,
+                       &stdout_fd, 1, noop_close, &expected_error);
+       LTTNG_ASSERT(!ret);
+
+       fd_tracker_destroy(tracker);
+       ret = rmdir(test_directory);
+       ok(ret == 0, "Test directory is empty");
+       free(test_directory);
+       free(unlinked_files_directory);
+}
+
+/*
+ * Validate that the tracker refuses to track two identical unsuspendable
+ * file descriptors.
+ */
+static
+void test_unsuspendable_duplicate(void)
+{
+       int ret, stdout_fd = fileno(stdout), out_fd;
+       struct fd_tracker *tracker;
+       char *test_directory = NULL, *unlinked_files_directory = NULL;
+
+       get_temporary_directories(&test_directory, &unlinked_files_directory);
+
+       tracker = fd_tracker_create(unlinked_files_directory, TRACKER_FD_LIMIT);
+       LTTNG_ASSERT(tracker);
+
+       ret = fd_tracker_open_unsuspendable_fd(tracker, &out_fd,
+                       NULL, 1, noop_open, &stdout_fd);
+       LTTNG_ASSERT(!ret);
+       ret = fd_tracker_open_unsuspendable_fd(tracker, &out_fd,
+                       NULL, 1, noop_open, &stdout_fd);
+       ok(ret == -EEXIST, "EEXIST reported on open of an already tracked file descriptor");
+
+       ret = fd_tracker_close_unsuspendable_fd(tracker,
+                       &stdout_fd, 1, noop_close, NULL);
+       LTTNG_ASSERT(!ret);
+
+       fd_tracker_destroy(tracker);
+       ret = rmdir(test_directory);
+       ok(ret == 0, "Test directory is empty");
+       free(test_directory);
+       free(unlinked_files_directory);
+}
+
+static
+int open_pipes(void *data, int *out_fds)
+{
+       unsigned int i;
+       const unsigned int pipe_count = TRACKER_FD_LIMIT / 2;
+
+       for (i = 0; i < pipe_count; i++) {
+               int ret = pipe(&out_fds[i * 2]);
+
+               if (ret) {
+                       return -errno;
+               }
+       }
+       return 0;
+}
+
+static
+int close_pipes(void *data, int *fds)
+{
+       int i;
+       int *pipes = fds;
+
+       for (i = 0; i < TRACKER_FD_LIMIT; i++) {
+               int ret = close(pipes[i]);
+
+               if (ret) {
+                       return -errno;
+               }
+       }
+       return 0;
+}
+
+/*
+ * Validate that the tracker enforces the open file descriptor limit
+ * when unsuspendable file descriptors are being opened.
+ */
+static
+void test_unsuspendable_limit(void)
+{
+       struct fd_tracker *tracker;
+       int ret, stdout_fd = fileno(stdout), out_fd;
+       int fds[TRACKER_FD_LIMIT];
+       char *test_directory = NULL, *unlinked_files_directory = NULL;
+
+       get_temporary_directories(&test_directory, &unlinked_files_directory);
+
+       /* This test assumes TRACKER_FD_LIMIT is a multiple of 2. */
+       LTTNG_ASSERT((TRACKER_FD_LIMIT % 2 == 0) && TRACKER_FD_LIMIT);
+
+       tracker = fd_tracker_create(unlinked_files_directory, TRACKER_FD_LIMIT);
+       LTTNG_ASSERT(tracker);
+
+       ret = fd_tracker_open_unsuspendable_fd(tracker, fds,
+                       NULL, TRACKER_FD_LIMIT, open_pipes, NULL);
+       ok(ret == 0, "File descriptor tracker allowed the user to meet its limit with unsuspendable file descriptors (%d)",
+                       TRACKER_FD_LIMIT);
+
+       ret = fd_tracker_open_unsuspendable_fd(tracker, &out_fd,
+                       NULL, 1, noop_open, &stdout_fd);
+       ok(ret == -EMFILE, "EMFILE reported when exceeding the file descriptor limit while opening an unsuspendable fd");
+
+       ret = fd_tracker_close_unsuspendable_fd(tracker,
+                       fds, TRACKER_FD_LIMIT, close_pipes, NULL);
+       LTTNG_ASSERT(!ret);
+
+       fd_tracker_destroy(tracker);
+       ret = rmdir(test_directory);
+       ok(ret == 0, "Test directory is empty");
+       free(test_directory);
+       free(unlinked_files_directory);
+}
+
+/*
+ * Validate that the tracker refuses to track two identical unsuspendable
+ * file descriptors.
+ */
+static
+void test_unsuspendable_close_untracked(void)
+{
+       int ret, stdout_fd = fileno(stdout), unknown_fds[2], out_fd;
+       struct fd_tracker *tracker;
+       char *test_directory = NULL, *unlinked_files_directory = NULL;
+
+       get_temporary_directories(&test_directory, &unlinked_files_directory);
+
+       tracker = fd_tracker_create(unlinked_files_directory, TRACKER_FD_LIMIT);
+       if (!tracker) {
+               goto end;;
+       }
+
+       ret = pipe(unknown_fds);
+       LTTNG_ASSERT(!ret);
+       ret = close(unknown_fds[0]);
+       LTTNG_ASSERT(ret == 0);
+       ret = close(unknown_fds[1]);
+       LTTNG_ASSERT(ret == 0);
+
+       ret = fd_tracker_open_unsuspendable_fd(tracker, &out_fd,
+                       NULL, 1, noop_open, &stdout_fd);
+       LTTNG_ASSERT(!ret);
+
+       ret = fd_tracker_close_unsuspendable_fd(tracker,
+                       unknown_fds, 1, noop_close, NULL);
+       ok(ret == -EINVAL, "EINVAL reported on close of an untracked file descriptor");
+
+       ret = fd_tracker_close_unsuspendable_fd(tracker,
+                       &stdout_fd, 1, noop_close, NULL);
+       LTTNG_ASSERT(!ret);
+
+       fd_tracker_destroy(tracker);
+       ret = rmdir(test_directory);
+       ok(ret == 0, "Test directory is empty");
+end:
+       free(test_directory);
+       free(unlinked_files_directory);
+}
+
+static int open_files(struct fd_tracker *tracker,
+               struct lttng_directory_handle *directory,
+               unsigned int count,
+               struct fs_handle **handles,
+               char **file_paths)
+{
+       int ret = 0;
+       unsigned int i;
+
+       for (i = 0; i < count; i++) {
+               int p_ret;
+               char *file_path;
+               struct fs_handle *handle;
+               mode_t mode = S_IWUSR | S_IRUSR;
+
+               p_ret = asprintf(&file_path, "file-%u", i);
+               LTTNG_ASSERT(p_ret >= 0);
+               file_paths[i] = file_path;
+
+               handle = fd_tracker_open_fs_handle(tracker, directory, file_path,
+                               O_RDWR | O_CREAT, &mode);
+               if (!handle) {
+                       ret = -1;
+                       break;
+               }
+               handles[i] = handle;
+       }
+       return ret;
+}
+
+static int open_same_file(struct fd_tracker *tracker,
+               struct lttng_directory_handle *directory,
+               const char *file,
+               unsigned int count,
+               struct fs_handle **handles)
+{
+       int ret = 0;
+       unsigned int i;
+
+       for (i = 0; i < count; i++) {
+               struct fs_handle *handle;
+               mode_t mode = S_IWUSR | S_IRUSR;
+
+               handle = fd_tracker_open_fs_handle(tracker, directory, file,
+                               O_RDWR | O_CREAT, &mode);
+               if (!handle) {
+                       ret = -1;
+                       break;
+               }
+               handles[i] = handle;
+       }
+       return ret;
+}
+
+static
+int cleanup_files(struct fd_tracker *tracker, const char *dir,
+               unsigned int count, struct fs_handle **handles,
+               char **file_paths)
+{
+       int ret = 0;
+       unsigned int i;
+
+       for (i = 0; i < count; i++) {
+               char *file_path = file_paths[i];
+
+               if (!file_path) {
+                       break;
+               }
+               if (fs_handle_unlink(handles[i])) {
+                       diag("Failed to unlink fs_handle to file %s", file_path);
+                       ret = -1;
+               }
+               if (fs_handle_close(handles[i])) {
+                       diag("Failed to close fs_handle to file %s", file_path);
+                       ret = -1;
+               }
+               free(file_path);
+       }
+       return ret;
+}
+
+static
+void test_suspendable_limit(void)
+{
+       int ret;
+       const int files_to_create = TRACKER_FD_LIMIT * 10;
+       struct fd_tracker *tracker;
+       char *test_directory = NULL, *unlinked_files_directory = NULL;
+       char *output_files[files_to_create];
+       struct fs_handle *handles[files_to_create];
+       struct lttng_directory_handle *dir_handle = NULL;
+       int dir_handle_fd_count;
+
+       memset(output_files, 0, sizeof(output_files));
+       memset(handles, 0, sizeof(handles));
+
+       get_temporary_directories(&test_directory, &unlinked_files_directory);
+
+       tracker = fd_tracker_create(unlinked_files_directory, TRACKER_FD_LIMIT);
+       if (!tracker) {
+               goto end;
+       }
+
+       dir_handle = lttng_directory_handle_create(test_directory);
+       LTTNG_ASSERT(dir_handle);
+       dir_handle_fd_count = !!lttng_directory_handle_uses_fd(dir_handle);
+
+       ret = open_files(tracker, dir_handle, files_to_create, handles,
+                       output_files);
+       ok(!ret, "Created %d files with a limit of %d simultaneously-opened file descriptor",
+                       files_to_create, TRACKER_FD_LIMIT);
+       check_fd_count(TRACKER_FD_LIMIT + STDIO_FD_COUNT + unknown_fds_count +
+                       dir_handle_fd_count);
+
+       ret = cleanup_files(tracker, test_directory, files_to_create, handles,
+                       output_files);
+       ok(!ret, "Close all opened filesystem handles");
+       ret = rmdir(test_directory);
+       ok(ret == 0, "Test directory is empty");
+       fd_tracker_destroy(tracker);
+       lttng_directory_handle_put(dir_handle);
+end:
+       free(test_directory);
+       free(unlinked_files_directory);
+}
+
+static
+void test_mixed_limit(void)
+{
+       int ret;
+       const int files_to_create = TRACKER_FD_LIMIT;
+       struct fd_tracker *tracker;
+       char *test_directory = NULL, *unlinked_files_directory = NULL;
+       char *output_files[files_to_create];
+       struct fs_handle *handles[files_to_create];
+       struct lttng_directory_handle *dir_handle = NULL;
+       int dir_handle_fd_count;
+
+       memset(output_files, 0, sizeof(output_files));
+       memset(handles, 0, sizeof(handles));
+
+       get_temporary_directories(&test_directory, &unlinked_files_directory);
+
+       tracker = fd_tracker_create(unlinked_files_directory, TRACKER_FD_LIMIT);
+       if (!tracker) {
+               goto end;
+       }
+
+       dir_handle = lttng_directory_handle_create(test_directory);
+       LTTNG_ASSERT(dir_handle);
+       dir_handle_fd_count = !!lttng_directory_handle_uses_fd(dir_handle);
+
+       ret = open_files(tracker, dir_handle, files_to_create, handles,
+                       output_files);
+       ok(!ret, "Created %d files with a limit of %d simultaneously-opened file descriptor",
+                       files_to_create, TRACKER_FD_LIMIT);
+       diag("Check file descriptor count after opening %u files", files_to_create);
+       check_fd_count(TRACKER_FD_LIMIT + STDIO_FD_COUNT + unknown_fds_count +
+                       dir_handle_fd_count);
+
+       /*
+        * Open unsuspendable fds (stdin, stdout, stderr) and verify that the fd
+        * cap is still respected.
+        */
+       diag("Check file descriptor count after adding %d unsuspendable fds",
+                       STDIO_FD_COUNT);
+       track_std_fds(tracker);
+       check_fd_count(TRACKER_FD_LIMIT + unknown_fds_count +
+                       dir_handle_fd_count);
+       diag("Untrack unsuspendable file descriptors");
+       untrack_std_fds(tracker);
+       check_fd_count(TRACKER_FD_LIMIT + unknown_fds_count +
+                       dir_handle_fd_count);
+
+       ret = cleanup_files(tracker, test_directory, files_to_create, handles,
+                       output_files);
+       ok(!ret, "Close all opened filesystem handles");
+       ret = rmdir(test_directory);
+       ok(ret == 0, "Test directory is empty");
+       fd_tracker_destroy(tracker);
+       lttng_directory_handle_put(dir_handle);
+end:
+       free(test_directory);
+       free(unlinked_files_directory);
+}
+
+/*
+ * Open more files than allowed by the fd tracker's cap and write,
+ * byte-by-byte, and in round-robin, a string. The goal is to force
+ * the fd tracker to suspend and resume the fs_handles often and
+ * verify that the fd cap is always respected.
+ *
+ * The content of the files is also verified at the end.
+ */
+static
+void test_suspendable_restore(void)
+{
+       int ret;
+       const int files_to_create = TRACKER_FD_LIMIT * 10;
+       struct fd_tracker *tracker;
+       char *output_files[files_to_create];
+       struct fs_handle *handles[files_to_create];
+       size_t content_index;
+       int handle_index;
+       bool write_success = true;
+       bool fd_cap_respected = true;
+       bool content_ok = true;
+       struct lttng_directory_handle *dir_handle = NULL;
+       int dir_handle_fd_count;
+       char *test_directory = NULL, *unlinked_files_directory = NULL;
+
+       memset(output_files, 0, sizeof(output_files));
+       memset(handles, 0, sizeof(handles));
+
+       get_temporary_directories(&test_directory, &unlinked_files_directory);
+
+       tracker = fd_tracker_create(unlinked_files_directory, TRACKER_FD_LIMIT);
+       if (!tracker) {
+               goto end;
+       }
+
+       dir_handle = lttng_directory_handle_create(test_directory);
+       LTTNG_ASSERT(dir_handle);
+       dir_handle_fd_count = !!lttng_directory_handle_uses_fd(dir_handle);
+
+       ret = open_files(tracker, dir_handle, files_to_create, handles,
+                       output_files);
+       ok(!ret, "Created %d files with a limit of %d simultaneously-opened file descriptor",
+                       files_to_create, TRACKER_FD_LIMIT);
+       diag("Check file descriptor count after opening %u files", files_to_create);
+       check_fd_count(TRACKER_FD_LIMIT + STDIO_FD_COUNT + unknown_fds_count +
+                       dir_handle_fd_count);
+
+       for (content_index = 0; content_index < sizeof(file_contents); content_index++) {
+               for (handle_index = 0; handle_index < files_to_create; handle_index++) {
+                       int fd;
+                       struct fs_handle *handle = handles[handle_index];
+                       const char *path = output_files[handle_index];
+
+                       fd = fs_handle_get_fd(handle);
+                       if (fd < 0) {
+                               write_success = false;
+                               diag("Failed to restore fs_handle to %s",
+                                               path);
+                               goto skip_write;
+                       }
+
+                       do {
+                               ret = write(fd, file_contents + content_index, 1);
+                       } while (ret < 0 && errno == EINTR);
+
+                       if (ret != 1) {
+                               write_success = false;
+                               PERROR("write() to %s failed", path);
+                               goto skip_write;
+                       }
+
+                       if (fd_count() > (TRACKER_FD_LIMIT + STDIO_FD_COUNT +
+                                                       unknown_fds_count +
+                                                       dir_handle_fd_count)) {
+                               fd_cap_respected = false;
+                       }
+
+                       fs_handle_put_fd(handle);
+               }
+       }
+skip_write:
+       ok(write_success, "Wrote reference string to %d files",
+                       files_to_create);
+       ok(fd_cap_respected, "FD tracker enforced the file descriptor cap");
+
+       /* Validate the contents of the files. */
+       for (handle_index = 0; handle_index < files_to_create; handle_index++) {
+               struct stat fd_stat;
+               const char *path = output_files[handle_index];
+               char read_buf[sizeof(file_contents)];
+               char *read_pos;
+               size_t to_read = sizeof(read_buf);
+               int fd;
+
+               fd = lttng_directory_handle_open_file(
+                               dir_handle, path, O_RDONLY, 0);
+               LTTNG_ASSERT(fd >= 0);
+               ret = fstat(fd, &fd_stat);
+               LTTNG_ASSERT(!ret);
+               if (fd_stat.st_size != sizeof(file_contents)) {
+                       diag("Content size of file %s doesn't match, got %" PRId64 ", expected %zu",
+                                       path, (int64_t) fd_stat.st_size,
+                                       sizeof(file_contents));
+                       content_ok = false;
+                       (void) close(fd);
+                       break;
+               }
+
+               read_pos = read_buf;
+               do {
+                       ret = read(fd, read_pos, to_read);
+                       if (ret > 0) {
+                               to_read -= ret;
+                               read_pos += ret;
+                       }
+               } while (to_read && (ret < 0 && errno == EINTR));
+               if (ret < 0) {
+                       content_ok = false;
+                       PERROR("Failed to read file %s", path);
+                       (void) close(fd);
+                       break;
+               }
+
+               if (strcmp(file_contents, read_buf)) {
+                       content_ok = false;
+                       diag("File content doesn't match the expectated string");
+                       (void) close(fd);
+                       break;
+               }
+               (void) close(fd);
+       }
+       ok(content_ok, "Files contain the expected content");
+       ret = cleanup_files(tracker, test_directory, files_to_create, handles,
+                       output_files);
+       ok(!ret, "Close all opened filesystem handles");
+       ret = rmdir(test_directory);
+       ok(ret == 0, "Test directory is empty");
+       fd_tracker_destroy(tracker);
+       lttng_directory_handle_put(dir_handle);
+end:
+       free(test_directory);
+       free(unlinked_files_directory);
+}
+
+static
+void test_unlink(void)
+{
+       int ret;
+       struct fd_tracker *tracker;
+       const int handles_to_open = 2;
+       struct fs_handle *handles[handles_to_open];
+       struct fs_handle *new_handle = NULL;
+       struct stat statbuf;
+       struct lttng_directory_handle *dir_handle = NULL;
+       const char file_name[] = "my_file";
+       char *test_directory = NULL, *unlinked_files_directory = NULL;
+       char *unlinked_file_zero = NULL, *unlinked_file_one = NULL;
+       int fd;
+
+       get_temporary_directories(&test_directory, &unlinked_files_directory);
+       ret = asprintf(&unlinked_file_zero, "%s/%u", unlinked_files_directory,
+                       0);
+       LTTNG_ASSERT(ret > 0);
+       ret = asprintf(&unlinked_file_one, "%s/%u", unlinked_files_directory,
+                       1);
+       LTTNG_ASSERT(ret > 0);
+
+       tracker = fd_tracker_create(unlinked_files_directory, 1);
+       if (!tracker) {
+               goto end;
+       }
+
+       dir_handle = lttng_directory_handle_create(test_directory);
+       LTTNG_ASSERT(dir_handle);
+
+       /* Open two handles to the same file. */
+       ret = open_same_file(tracker, dir_handle, file_name, handles_to_open,
+                       handles);
+       ok(!ret, "Successfully opened %i handles to %s/%s", handles_to_open,
+                       test_directory, file_name);
+       if (ret) {
+               goto end;
+       }
+
+       /*
+        * Unlinking the first handle should cause the file to be renamed
+        * to '0'.
+        */
+       ret = fs_handle_unlink(handles[0]);
+       ok(!ret, "Successfully unlinked the first handle to %s/%s",
+                       test_directory, file_name);
+
+       /*
+        * The original file should no longer exist on the file system, and a
+        * new file named '0' should exist.
+        */
+       ok(lttng_directory_handle_stat(dir_handle, file_name, &statbuf) == -1 &&
+                                       errno == ENOENT,
+                       "%s no longer present on file system after unlink",
+                       file_name);
+       ok(lttng_directory_handle_stat(
+                       dir_handle, unlinked_file_zero, &statbuf) == 0,
+                       "%s exists on file system after unlink",
+                       unlinked_file_zero);
+
+       /*
+        * It should be possible to use the file descriptors of both handles.
+        * Since only one file descriptor can be opened at once, this should
+        * force the fd_tracker to suspend and restore the handles.
+        */
+       fd = fs_handle_get_fd(handles[0]);
+       ok(fd >= 0, "Got fd from first handle");
+
+       fd = fs_handle_get_fd(handles[1]);
+       ok (fd < 0, "fd tracker does not allow two fds to be used at once");
+
+       fs_handle_put_fd(handles[0]);
+       fd = fs_handle_get_fd(handles[1]);
+       ok(fd >= 0, "Got fd from second handle");
+       fs_handle_put_fd(handles[1]);
+
+       /* The second unlink should fail with -ENOENT. */
+       ret = fs_handle_unlink(handles[1]);
+       ok(ret == -ENOENT,
+                       "ENOENT is reported when attempting to unlink the second handle to %s/%s",
+                       test_directory, file_name);
+
+       /*
+        * Opening a new handle to 'my_file' should succeed.
+        */
+       ret = open_same_file(tracker, dir_handle, file_name, 1, &new_handle);
+       ok(!ret, "Successfully opened a new handle to previously unlinked file %s/%s",
+                       test_directory, file_name);
+       LTTNG_ASSERT(new_handle);
+
+       /*
+        * Unlinking the new handle should cause the file to be renamed
+        * to '1' since '0' already exists.
+        */
+       ret = fs_handle_unlink(new_handle);
+       ok(!ret, "Successfully unlinked the new handle handle to %s/%s",
+                       test_directory, file_name);
+       ok(stat(unlinked_file_one, &statbuf) == 0,
+                       "%s exists on file system after unlink",
+                       unlinked_file_one);
+
+       ret = fs_handle_close(handles[0]);
+       ok(!ret, "Successfully closed the first handle");
+       ret = fs_handle_close(handles[1]);
+       ok(!ret, "Successfully closed the second handle");
+       ret = fs_handle_close(new_handle);
+       ok(!ret, "Successfully closed the third handle");
+
+       ok(lttng_directory_handle_stat(dir_handle, file_name, &statbuf) == -1 &&
+                                       errno == ENOENT,
+                       "%s no longer present on file system after handle close",
+                       file_name);
+       ok(lttng_directory_handle_stat(
+                       dir_handle, unlinked_file_zero, &statbuf) == -1 &&
+                                       errno == ENOENT,
+                       "%s no longer present on file system after handle close",
+                       unlinked_file_zero);
+       ok(lttng_directory_handle_stat(dir_handle, unlinked_file_one,
+                       &statbuf) == -1 &&
+                                       errno == ENOENT,
+                       "%s no longer present on file system after handle close",
+                       unlinked_file_one);
+
+       ret = rmdir(test_directory);
+       ok(ret == 0, "Test directory is empty");
+end:
+       fd_tracker_destroy(tracker);
+       free(test_directory);
+       free(unlinked_files_directory);
+       free(unlinked_file_zero);
+       free(unlinked_file_one);
+       lttng_directory_handle_put(dir_handle);
+}
+
+int main(int argc, char **argv)
+{
+       plan_tests(NUM_TESTS);
+       diag("File descriptor tracker unit tests");
+
+       rcu_register_thread();
+
+       unknown_fds_count = fd_count() - STDIO_FD_COUNT;
+       LTTNG_ASSERT(unknown_fds_count >= 0);
+
+       diag("Unsuspendable - basic");
+       test_unsuspendable_basic();
+       diag("Unsuspendable - callback return values");
+       test_unsuspendable_cb_return();
+       diag("Unsuspendable - duplicate file descriptors");
+       test_unsuspendable_duplicate();
+       diag("Unsuspendable - closing an untracked file descriptor");
+       test_unsuspendable_close_untracked();
+       diag("Unsuspendable - check that file descriptor limit is enforced");
+       test_unsuspendable_limit();
+
+       diag("Suspendable - check that file descriptor limit is enforced");
+       test_suspendable_limit();
+       diag("Suspendable - restoration test");
+       test_suspendable_restore();
+
+       diag("Mixed - check that file descriptor limit is enforced");
+       test_mixed_limit();
+
+       diag("Suspendable - Unlinking test");
+       test_unlink();
+
+       rcu_barrier();
+       rcu_unregister_thread();
+       return exit_status();
+}
diff --git a/tests/unit/test_kernel_probe.c b/tests/unit/test_kernel_probe.c
deleted file mode 100644 (file)
index 0f6f89e..0000000
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Unit tests for the kernel probe location API.
- *
- * Copyright (C) 2020 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- */
-
-#include <inttypes.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <tap/tap.h>
-
-#include <common/payload-view.h>
-#include <common/payload.h>
-#include <lttng/kernel-probe-internal.h>
-#include <lttng/kernel-probe.h>
-
-/* For error.h */
-int lttng_opt_quiet = 1;
-int lttng_opt_verbose;
-int lttng_opt_mi;
-
-#define NUM_TESTS 24
-
-static void test_kernel_probe_location_address(void)
-{
-       struct lttng_kernel_probe_location *location = NULL;
-       struct lttng_kernel_probe_location *location_from_buffer = NULL;
-       enum lttng_kernel_probe_location_status status;
-       enum lttng_kernel_probe_location_type type;
-       uint64_t address = 50, _address;
-       struct lttng_payload payload;
-
-       diag("Testing kernel probe location address");
-
-       lttng_payload_init(&payload);
-
-       location = lttng_kernel_probe_location_address_create(address);
-       ok(location, "Location object");
-
-       type = lttng_kernel_probe_location_get_type(location);
-       ok(LTTNG_KERNEL_PROBE_LOCATION_TYPE_ADDRESS == type,
-                       "Location type got %d expected %d", type,
-                       LTTNG_KERNEL_PROBE_LOCATION_TYPE_ADDRESS);
-
-       status = lttng_kernel_probe_location_address_get_address(
-                       location, &_address);
-       ok(status == LTTNG_KERNEL_PROBE_LOCATION_STATUS_OK, "Getting address");
-       ok(address == _address,
-                       "Address is equal. Got %" PRIu64 " expected %" PRIu64,
-                       _address, address);
-
-       ok(lttng_kernel_probe_location_serialize(location, &payload) > 0,
-                       "Serializing");
-       {
-               struct lttng_payload_view view =
-                               lttng_payload_view_from_payload(
-                                               &payload, 0, -1);
-               ok(lttng_kernel_probe_location_create_from_payload(
-                                  &view, &location_from_buffer) > 0,
-                               "Deserializing");
-       }
-
-       type = lttng_kernel_probe_location_get_type(location_from_buffer);
-       ok(LTTNG_KERNEL_PROBE_LOCATION_TYPE_ADDRESS == type,
-                       "Location from buffer type got %d expected %d", type,
-                       LTTNG_KERNEL_PROBE_LOCATION_TYPE_ADDRESS);
-
-       status = lttng_kernel_probe_location_address_get_address(
-                       location_from_buffer, &_address);
-       ok(status == LTTNG_KERNEL_PROBE_LOCATION_STATUS_OK, "Getting address");
-       ok(address == _address,
-                       "Address from buffer is equal. Got %" PRIu64
-                       " expected %" PRIu64,
-                       _address, address);
-
-       ok(lttng_kernel_probe_location_is_equal(location, location_from_buffer),
-                       "serialized and from buffer are equal");
-
-       lttng_payload_reset(&payload);
-       lttng_kernel_probe_location_destroy(location);
-       lttng_kernel_probe_location_destroy(location_from_buffer);
-}
-
-static void test_kernel_probe_location_symbol(void)
-{
-       struct lttng_kernel_probe_location *location = NULL;
-       struct lttng_kernel_probe_location *location_from_buffer = NULL;
-       enum lttng_kernel_probe_location_status status;
-       enum lttng_kernel_probe_location_type type;
-       uint64_t offset = 50, _offset;
-       const char *symbol = "Une_bonne", *_symbol;
-       struct lttng_payload payload;
-
-       diag("Testing kernel probe location symbol");
-
-       lttng_payload_init(&payload);
-
-       location = lttng_kernel_probe_location_symbol_create(symbol, offset);
-       ok(location, "Location object");
-
-       type = lttng_kernel_probe_location_get_type(location);
-       ok(LTTNG_KERNEL_PROBE_LOCATION_TYPE_SYMBOL_OFFSET == type,
-                       "Location type got %d expected %d", type,
-                       LTTNG_KERNEL_PROBE_LOCATION_TYPE_SYMBOL_OFFSET);
-
-       _symbol = lttng_kernel_probe_location_symbol_get_name(location);
-       ok(_symbol, "Getting symbol name");
-       ok(!strncmp(symbol, _symbol, strlen(symbol)),
-                       "Symbol name is equal. Got %s, expected %s", _symbol,
-                       symbol);
-
-       status = lttng_kernel_probe_location_symbol_get_offset(
-                       location, &_offset);
-       ok(status == LTTNG_KERNEL_PROBE_LOCATION_STATUS_OK, "Getting offset");
-       ok(offset == _offset,
-                       "Offset is equal. Got %" PRIu64 " expected %" PRIu64,
-                       _offset, offset);
-
-       ok(lttng_kernel_probe_location_serialize(location, &payload) > 0,
-                       "Serializing");
-       {
-               struct lttng_payload_view view =
-                               lttng_payload_view_from_payload(
-                                               &payload, 0, -1);
-               ok(lttng_kernel_probe_location_create_from_payload(
-                                  &view, &location_from_buffer) > 0,
-                               "Deserializing");
-       }
-
-       type = lttng_kernel_probe_location_get_type(location_from_buffer);
-       ok(LTTNG_KERNEL_PROBE_LOCATION_TYPE_SYMBOL_OFFSET == type,
-                       "Location from buffer type got %d expected %d", type,
-                       LTTNG_KERNEL_PROBE_LOCATION_TYPE_SYMBOL_OFFSET);
-
-       _symbol = lttng_kernel_probe_location_symbol_get_name(
-                       location_from_buffer);
-       ok(_symbol, "Getting symbol name");
-       ok(!strncmp(symbol, _symbol, strlen(symbol)),
-                       "Symbol name is equal. Got %s, expected %s", _symbol,
-                       symbol);
-
-       status = lttng_kernel_probe_location_symbol_get_offset(
-                       location_from_buffer, &_offset);
-       ok(status == LTTNG_KERNEL_PROBE_LOCATION_STATUS_OK, "Getting offset");
-       ok(offset == _offset,
-                       "Offset is equal. Got %" PRIu64 " expected %" PRIu64,
-                       _offset, offset);
-
-       ok(lttng_kernel_probe_location_is_equal(location, location_from_buffer),
-                       "serialized and from buffer are equal");
-
-       lttng_payload_reset(&payload);
-       lttng_kernel_probe_location_destroy(location);
-       lttng_kernel_probe_location_destroy(location_from_buffer);
-}
-
-int main(int argc, const char *argv[])
-{
-       plan_tests(NUM_TESTS);
-       test_kernel_probe_location_address();
-       test_kernel_probe_location_symbol();
-       return exit_status();
-}
diff --git a/tests/unit/test_kernel_probe.cpp b/tests/unit/test_kernel_probe.cpp
new file mode 100644 (file)
index 0000000..0f6f89e
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * Unit tests for the kernel probe location API.
+ *
+ * Copyright (C) 2020 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <tap/tap.h>
+
+#include <common/payload-view.h>
+#include <common/payload.h>
+#include <lttng/kernel-probe-internal.h>
+#include <lttng/kernel-probe.h>
+
+/* For error.h */
+int lttng_opt_quiet = 1;
+int lttng_opt_verbose;
+int lttng_opt_mi;
+
+#define NUM_TESTS 24
+
+static void test_kernel_probe_location_address(void)
+{
+       struct lttng_kernel_probe_location *location = NULL;
+       struct lttng_kernel_probe_location *location_from_buffer = NULL;
+       enum lttng_kernel_probe_location_status status;
+       enum lttng_kernel_probe_location_type type;
+       uint64_t address = 50, _address;
+       struct lttng_payload payload;
+
+       diag("Testing kernel probe location address");
+
+       lttng_payload_init(&payload);
+
+       location = lttng_kernel_probe_location_address_create(address);
+       ok(location, "Location object");
+
+       type = lttng_kernel_probe_location_get_type(location);
+       ok(LTTNG_KERNEL_PROBE_LOCATION_TYPE_ADDRESS == type,
+                       "Location type got %d expected %d", type,
+                       LTTNG_KERNEL_PROBE_LOCATION_TYPE_ADDRESS);
+
+       status = lttng_kernel_probe_location_address_get_address(
+                       location, &_address);
+       ok(status == LTTNG_KERNEL_PROBE_LOCATION_STATUS_OK, "Getting address");
+       ok(address == _address,
+                       "Address is equal. Got %" PRIu64 " expected %" PRIu64,
+                       _address, address);
+
+       ok(lttng_kernel_probe_location_serialize(location, &payload) > 0,
+                       "Serializing");
+       {
+               struct lttng_payload_view view =
+                               lttng_payload_view_from_payload(
+                                               &payload, 0, -1);
+               ok(lttng_kernel_probe_location_create_from_payload(
+                                  &view, &location_from_buffer) > 0,
+                               "Deserializing");
+       }
+
+       type = lttng_kernel_probe_location_get_type(location_from_buffer);
+       ok(LTTNG_KERNEL_PROBE_LOCATION_TYPE_ADDRESS == type,
+                       "Location from buffer type got %d expected %d", type,
+                       LTTNG_KERNEL_PROBE_LOCATION_TYPE_ADDRESS);
+
+       status = lttng_kernel_probe_location_address_get_address(
+                       location_from_buffer, &_address);
+       ok(status == LTTNG_KERNEL_PROBE_LOCATION_STATUS_OK, "Getting address");
+       ok(address == _address,
+                       "Address from buffer is equal. Got %" PRIu64
+                       " expected %" PRIu64,
+                       _address, address);
+
+       ok(lttng_kernel_probe_location_is_equal(location, location_from_buffer),
+                       "serialized and from buffer are equal");
+
+       lttng_payload_reset(&payload);
+       lttng_kernel_probe_location_destroy(location);
+       lttng_kernel_probe_location_destroy(location_from_buffer);
+}
+
+static void test_kernel_probe_location_symbol(void)
+{
+       struct lttng_kernel_probe_location *location = NULL;
+       struct lttng_kernel_probe_location *location_from_buffer = NULL;
+       enum lttng_kernel_probe_location_status status;
+       enum lttng_kernel_probe_location_type type;
+       uint64_t offset = 50, _offset;
+       const char *symbol = "Une_bonne", *_symbol;
+       struct lttng_payload payload;
+
+       diag("Testing kernel probe location symbol");
+
+       lttng_payload_init(&payload);
+
+       location = lttng_kernel_probe_location_symbol_create(symbol, offset);
+       ok(location, "Location object");
+
+       type = lttng_kernel_probe_location_get_type(location);
+       ok(LTTNG_KERNEL_PROBE_LOCATION_TYPE_SYMBOL_OFFSET == type,
+                       "Location type got %d expected %d", type,
+                       LTTNG_KERNEL_PROBE_LOCATION_TYPE_SYMBOL_OFFSET);
+
+       _symbol = lttng_kernel_probe_location_symbol_get_name(location);
+       ok(_symbol, "Getting symbol name");
+       ok(!strncmp(symbol, _symbol, strlen(symbol)),
+                       "Symbol name is equal. Got %s, expected %s", _symbol,
+                       symbol);
+
+       status = lttng_kernel_probe_location_symbol_get_offset(
+                       location, &_offset);
+       ok(status == LTTNG_KERNEL_PROBE_LOCATION_STATUS_OK, "Getting offset");
+       ok(offset == _offset,
+                       "Offset is equal. Got %" PRIu64 " expected %" PRIu64,
+                       _offset, offset);
+
+       ok(lttng_kernel_probe_location_serialize(location, &payload) > 0,
+                       "Serializing");
+       {
+               struct lttng_payload_view view =
+                               lttng_payload_view_from_payload(
+                                               &payload, 0, -1);
+               ok(lttng_kernel_probe_location_create_from_payload(
+                                  &view, &location_from_buffer) > 0,
+                               "Deserializing");
+       }
+
+       type = lttng_kernel_probe_location_get_type(location_from_buffer);
+       ok(LTTNG_KERNEL_PROBE_LOCATION_TYPE_SYMBOL_OFFSET == type,
+                       "Location from buffer type got %d expected %d", type,
+                       LTTNG_KERNEL_PROBE_LOCATION_TYPE_SYMBOL_OFFSET);
+
+       _symbol = lttng_kernel_probe_location_symbol_get_name(
+                       location_from_buffer);
+       ok(_symbol, "Getting symbol name");
+       ok(!strncmp(symbol, _symbol, strlen(symbol)),
+                       "Symbol name is equal. Got %s, expected %s", _symbol,
+                       symbol);
+
+       status = lttng_kernel_probe_location_symbol_get_offset(
+                       location_from_buffer, &_offset);
+       ok(status == LTTNG_KERNEL_PROBE_LOCATION_STATUS_OK, "Getting offset");
+       ok(offset == _offset,
+                       "Offset is equal. Got %" PRIu64 " expected %" PRIu64,
+                       _offset, offset);
+
+       ok(lttng_kernel_probe_location_is_equal(location, location_from_buffer),
+                       "serialized and from buffer are equal");
+
+       lttng_payload_reset(&payload);
+       lttng_kernel_probe_location_destroy(location);
+       lttng_kernel_probe_location_destroy(location_from_buffer);
+}
+
+int main(int argc, const char *argv[])
+{
+       plan_tests(NUM_TESTS);
+       test_kernel_probe_location_address();
+       test_kernel_probe_location_symbol();
+       return exit_status();
+}
diff --git a/tests/unit/test_log_level_rule.c b/tests/unit/test_log_level_rule.c
deleted file mode 100644 (file)
index d2895c8..0000000
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Unit tests for the log level rule API.
- *
- * Copyright (C) 2020 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- */
-
-#include <inttypes.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <tap/tap.h>
-
-#include <common/payload-view.h>
-#include <common/payload.h>
-#include <lttng/log-level-rule-internal.h>
-#include <lttng/log-level-rule.h>
-
-/* For error.h. */
-int lttng_opt_quiet = 1;
-int lttng_opt_verbose;
-int lttng_opt_mi;
-
-#define NUM_TESTS 29
-
-static void test_log_level_rule_error(void)
-{
-       int level = 9000;
-       struct lttng_log_level_rule *exactly =
-                       lttng_log_level_rule_exactly_create(level);
-       struct lttng_log_level_rule *at_least_as_severe =
-                       lttng_log_level_rule_at_least_as_severe_as_create(
-                                       level);
-
-       ok(lttng_log_level_rule_get_type(NULL) == LTTNG_LOG_LEVEL_RULE_TYPE_UNKNOWN, "Get type on invalid pointer");
-
-       ok(lttng_log_level_rule_exactly_get_level(NULL, NULL) == LTTNG_LOG_LEVEL_RULE_STATUS_INVALID, "lttng_log_level_rule_exactly_get_level (NULL, NULL) returns invalid");
-       ok(lttng_log_level_rule_exactly_get_level(exactly, NULL) == LTTNG_LOG_LEVEL_RULE_STATUS_INVALID, "lttng_log_level_rule_exactly_get_level (valid, NULL) returns invalid");
-       ok(lttng_log_level_rule_exactly_get_level(NULL, &level) == LTTNG_LOG_LEVEL_RULE_STATUS_INVALID, "lttng_log_level_rule_exactly_get_level (NULL, valid) returns invalid");
-
-       ok(lttng_log_level_rule_at_least_as_severe_as_get_level(NULL, NULL) == LTTNG_LOG_LEVEL_RULE_STATUS_INVALID, "lttng_log_level_rule_at_least_as_severe_as_get_level (NULL, NULL) returns invalid");
-       ok(lttng_log_level_rule_at_least_as_severe_as_get_level(exactly, NULL) == LTTNG_LOG_LEVEL_RULE_STATUS_INVALID, "lttng_log_level_rule_at_least_as_severe_as_get_level (valid, NULL) returns invalid");
-       ok(lttng_log_level_rule_at_least_as_severe_as_get_level(NULL, &level) == LTTNG_LOG_LEVEL_RULE_STATUS_INVALID, "lttng_log_level_rule_at_least_as_severe_as_get_level (NULL, valid) returns invalid");
-
-       lttng_log_level_rule_destroy(exactly);
-       lttng_log_level_rule_destroy(at_least_as_severe);
-}
-
-static
-void test_log_level_rule_serialize_deserialize(const struct lttng_log_level_rule *rule)
-{
-       struct lttng_log_level_rule *log_level_rule_from_buffer = NULL;
-       struct lttng_payload payload;
-
-       lttng_payload_init(&payload);
-
-       ok(lttng_log_level_rule_serialize(rule, &payload) == 0, "Serializing.");
-
-       {
-               struct lttng_payload_view view =
-                               lttng_payload_view_from_payload(
-                                               &payload, 0, -1);
-
-               ok(lttng_log_level_rule_create_from_payload(
-                               &view, &log_level_rule_from_buffer) > 0,
-                               "Deserializing.");
-       }
-
-       ok(lttng_log_level_rule_is_equal(rule, log_level_rule_from_buffer), "Serialized and from buffer are equal");
-
-       lttng_log_level_rule_destroy(log_level_rule_from_buffer);
-}
-
-static
-void test_log_level_rule_is_equal_exactly(void)
-{
-       int level = 9000, no_eq_level = 420;
-       struct lttng_log_level_rule *a, *b, *different_level, *different_type;
-
-       /* Identical log level rules. */
-       a = lttng_log_level_rule_exactly_create(level);
-       b = lttng_log_level_rule_exactly_create(level);
-
-       /* Different level, same type. */
-       different_level = lttng_log_level_rule_exactly_create(no_eq_level);
-
-       /* Different type. */
-       different_type = lttng_log_level_rule_at_least_as_severe_as_create(level);
-
-       LTTNG_ASSERT(a && b && different_level && different_type);
-
-       ok(lttng_log_level_rule_is_equal(a, a), "Same object is equal");
-       ok(lttng_log_level_rule_is_equal(a, b), "Object a and b are equal");
-       ok(!lttng_log_level_rule_is_equal(a, different_level), " Object of different levels are not equal");
-       ok(!lttng_log_level_rule_is_equal(a, different_type), " Object of different types are not equal");
-
-       lttng_log_level_rule_destroy(a);
-       lttng_log_level_rule_destroy(b);
-       lttng_log_level_rule_destroy(different_level);
-       lttng_log_level_rule_destroy(different_type);
-}
-
-static
-void test_log_level_rule_is_equal_at_least_as_severe_as(void)
-{
-       int level = 9000, no_eq_level = 420;
-       struct lttng_log_level_rule *a, *b, *different_level, *different_type;
-
-       /* Identical log level rules. */
-       a = lttng_log_level_rule_at_least_as_severe_as_create(level);
-       b = lttng_log_level_rule_at_least_as_severe_as_create(level);
-
-       /* Different level, same type. */
-       different_level = lttng_log_level_rule_at_least_as_severe_as_create(no_eq_level);
-
-       /* Different type. */
-       different_type = lttng_log_level_rule_exactly_create(level);
-
-       LTTNG_ASSERT(a && b && different_level && different_type);
-
-       ok(lttng_log_level_rule_is_equal(a, a), "Same object is equal");
-       ok(lttng_log_level_rule_is_equal(a, b), "Object a and b are equal");
-       ok(!lttng_log_level_rule_is_equal(a, different_level), " Object of different levels are not equal");
-       ok(!lttng_log_level_rule_is_equal(a, different_type), " Object of different types are not equal");
-
-       lttng_log_level_rule_destroy(a);
-       lttng_log_level_rule_destroy(b);
-       lttng_log_level_rule_destroy(different_level);
-       lttng_log_level_rule_destroy(different_type);
-}
-
-static void test_log_level_rule_exactly(void)
-{
-       int level = 9000;
-       int _level;
-       struct lttng_log_level_rule *exactly = NULL;
-       enum lttng_log_level_rule_status status;
-
-       exactly = lttng_log_level_rule_exactly_create(level);
-
-       ok(exactly, "Log level exactly allocated");
-       ok(lttng_log_level_rule_get_type(exactly) ==
-                                       LTTNG_LOG_LEVEL_RULE_TYPE_EXACTLY,
-                       "Log level rule exactly type");
-
-       status = lttng_log_level_rule_exactly_get_level(exactly, &_level);
-       ok(status == LTTNG_LOG_LEVEL_RULE_STATUS_OK, "Get the level");
-       ok(_level == level, "Level property is valid");
-
-       test_log_level_rule_is_equal_exactly();
-       test_log_level_rule_serialize_deserialize(exactly);
-       lttng_log_level_rule_destroy(exactly);
-}
-
-static void test_log_level_rule_at_least_as_severe_as(void)
-{
-       int level = 9000;
-       int _level;
-       struct lttng_log_level_rule *at_least_as_severe_as = NULL;
-       enum lttng_log_level_rule_status status;
-
-       at_least_as_severe_as = lttng_log_level_rule_at_least_as_severe_as_create(level);
-
-       ok(at_least_as_severe_as, "Log level at_least_as_severe_as allocated");
-       ok(lttng_log_level_rule_get_type(at_least_as_severe_as) ==
-                                       LTTNG_LOG_LEVEL_RULE_TYPE_AT_LEAST_AS_SEVERE_AS,
-                       "Log level rule at_least_as_severe_as type");
-
-       status = lttng_log_level_rule_at_least_as_severe_as_get_level(at_least_as_severe_as, &_level);
-       ok(status == LTTNG_LOG_LEVEL_RULE_STATUS_OK, "Get the level");
-       ok(_level == level, "Level property is valid");
-
-       test_log_level_rule_is_equal_at_least_as_severe_as();
-       test_log_level_rule_serialize_deserialize(at_least_as_severe_as);
-       lttng_log_level_rule_destroy(at_least_as_severe_as);
-}
-
-int main(int argc, const char *argv[])
-{
-       plan_tests(NUM_TESTS);
-       test_log_level_rule_exactly();
-       test_log_level_rule_at_least_as_severe_as();
-       test_log_level_rule_error();
-       return exit_status();
-}
diff --git a/tests/unit/test_log_level_rule.cpp b/tests/unit/test_log_level_rule.cpp
new file mode 100644 (file)
index 0000000..d2895c8
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * Unit tests for the log level rule API.
+ *
+ * Copyright (C) 2020 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <tap/tap.h>
+
+#include <common/payload-view.h>
+#include <common/payload.h>
+#include <lttng/log-level-rule-internal.h>
+#include <lttng/log-level-rule.h>
+
+/* For error.h. */
+int lttng_opt_quiet = 1;
+int lttng_opt_verbose;
+int lttng_opt_mi;
+
+#define NUM_TESTS 29
+
+static void test_log_level_rule_error(void)
+{
+       int level = 9000;
+       struct lttng_log_level_rule *exactly =
+                       lttng_log_level_rule_exactly_create(level);
+       struct lttng_log_level_rule *at_least_as_severe =
+                       lttng_log_level_rule_at_least_as_severe_as_create(
+                                       level);
+
+       ok(lttng_log_level_rule_get_type(NULL) == LTTNG_LOG_LEVEL_RULE_TYPE_UNKNOWN, "Get type on invalid pointer");
+
+       ok(lttng_log_level_rule_exactly_get_level(NULL, NULL) == LTTNG_LOG_LEVEL_RULE_STATUS_INVALID, "lttng_log_level_rule_exactly_get_level (NULL, NULL) returns invalid");
+       ok(lttng_log_level_rule_exactly_get_level(exactly, NULL) == LTTNG_LOG_LEVEL_RULE_STATUS_INVALID, "lttng_log_level_rule_exactly_get_level (valid, NULL) returns invalid");
+       ok(lttng_log_level_rule_exactly_get_level(NULL, &level) == LTTNG_LOG_LEVEL_RULE_STATUS_INVALID, "lttng_log_level_rule_exactly_get_level (NULL, valid) returns invalid");
+
+       ok(lttng_log_level_rule_at_least_as_severe_as_get_level(NULL, NULL) == LTTNG_LOG_LEVEL_RULE_STATUS_INVALID, "lttng_log_level_rule_at_least_as_severe_as_get_level (NULL, NULL) returns invalid");
+       ok(lttng_log_level_rule_at_least_as_severe_as_get_level(exactly, NULL) == LTTNG_LOG_LEVEL_RULE_STATUS_INVALID, "lttng_log_level_rule_at_least_as_severe_as_get_level (valid, NULL) returns invalid");
+       ok(lttng_log_level_rule_at_least_as_severe_as_get_level(NULL, &level) == LTTNG_LOG_LEVEL_RULE_STATUS_INVALID, "lttng_log_level_rule_at_least_as_severe_as_get_level (NULL, valid) returns invalid");
+
+       lttng_log_level_rule_destroy(exactly);
+       lttng_log_level_rule_destroy(at_least_as_severe);
+}
+
+static
+void test_log_level_rule_serialize_deserialize(const struct lttng_log_level_rule *rule)
+{
+       struct lttng_log_level_rule *log_level_rule_from_buffer = NULL;
+       struct lttng_payload payload;
+
+       lttng_payload_init(&payload);
+
+       ok(lttng_log_level_rule_serialize(rule, &payload) == 0, "Serializing.");
+
+       {
+               struct lttng_payload_view view =
+                               lttng_payload_view_from_payload(
+                                               &payload, 0, -1);
+
+               ok(lttng_log_level_rule_create_from_payload(
+                               &view, &log_level_rule_from_buffer) > 0,
+                               "Deserializing.");
+       }
+
+       ok(lttng_log_level_rule_is_equal(rule, log_level_rule_from_buffer), "Serialized and from buffer are equal");
+
+       lttng_log_level_rule_destroy(log_level_rule_from_buffer);
+}
+
+static
+void test_log_level_rule_is_equal_exactly(void)
+{
+       int level = 9000, no_eq_level = 420;
+       struct lttng_log_level_rule *a, *b, *different_level, *different_type;
+
+       /* Identical log level rules. */
+       a = lttng_log_level_rule_exactly_create(level);
+       b = lttng_log_level_rule_exactly_create(level);
+
+       /* Different level, same type. */
+       different_level = lttng_log_level_rule_exactly_create(no_eq_level);
+
+       /* Different type. */
+       different_type = lttng_log_level_rule_at_least_as_severe_as_create(level);
+
+       LTTNG_ASSERT(a && b && different_level && different_type);
+
+       ok(lttng_log_level_rule_is_equal(a, a), "Same object is equal");
+       ok(lttng_log_level_rule_is_equal(a, b), "Object a and b are equal");
+       ok(!lttng_log_level_rule_is_equal(a, different_level), " Object of different levels are not equal");
+       ok(!lttng_log_level_rule_is_equal(a, different_type), " Object of different types are not equal");
+
+       lttng_log_level_rule_destroy(a);
+       lttng_log_level_rule_destroy(b);
+       lttng_log_level_rule_destroy(different_level);
+       lttng_log_level_rule_destroy(different_type);
+}
+
+static
+void test_log_level_rule_is_equal_at_least_as_severe_as(void)
+{
+       int level = 9000, no_eq_level = 420;
+       struct lttng_log_level_rule *a, *b, *different_level, *different_type;
+
+       /* Identical log level rules. */
+       a = lttng_log_level_rule_at_least_as_severe_as_create(level);
+       b = lttng_log_level_rule_at_least_as_severe_as_create(level);
+
+       /* Different level, same type. */
+       different_level = lttng_log_level_rule_at_least_as_severe_as_create(no_eq_level);
+
+       /* Different type. */
+       different_type = lttng_log_level_rule_exactly_create(level);
+
+       LTTNG_ASSERT(a && b && different_level && different_type);
+
+       ok(lttng_log_level_rule_is_equal(a, a), "Same object is equal");
+       ok(lttng_log_level_rule_is_equal(a, b), "Object a and b are equal");
+       ok(!lttng_log_level_rule_is_equal(a, different_level), " Object of different levels are not equal");
+       ok(!lttng_log_level_rule_is_equal(a, different_type), " Object of different types are not equal");
+
+       lttng_log_level_rule_destroy(a);
+       lttng_log_level_rule_destroy(b);
+       lttng_log_level_rule_destroy(different_level);
+       lttng_log_level_rule_destroy(different_type);
+}
+
+static void test_log_level_rule_exactly(void)
+{
+       int level = 9000;
+       int _level;
+       struct lttng_log_level_rule *exactly = NULL;
+       enum lttng_log_level_rule_status status;
+
+       exactly = lttng_log_level_rule_exactly_create(level);
+
+       ok(exactly, "Log level exactly allocated");
+       ok(lttng_log_level_rule_get_type(exactly) ==
+                                       LTTNG_LOG_LEVEL_RULE_TYPE_EXACTLY,
+                       "Log level rule exactly type");
+
+       status = lttng_log_level_rule_exactly_get_level(exactly, &_level);
+       ok(status == LTTNG_LOG_LEVEL_RULE_STATUS_OK, "Get the level");
+       ok(_level == level, "Level property is valid");
+
+       test_log_level_rule_is_equal_exactly();
+       test_log_level_rule_serialize_deserialize(exactly);
+       lttng_log_level_rule_destroy(exactly);
+}
+
+static void test_log_level_rule_at_least_as_severe_as(void)
+{
+       int level = 9000;
+       int _level;
+       struct lttng_log_level_rule *at_least_as_severe_as = NULL;
+       enum lttng_log_level_rule_status status;
+
+       at_least_as_severe_as = lttng_log_level_rule_at_least_as_severe_as_create(level);
+
+       ok(at_least_as_severe_as, "Log level at_least_as_severe_as allocated");
+       ok(lttng_log_level_rule_get_type(at_least_as_severe_as) ==
+                                       LTTNG_LOG_LEVEL_RULE_TYPE_AT_LEAST_AS_SEVERE_AS,
+                       "Log level rule at_least_as_severe_as type");
+
+       status = lttng_log_level_rule_at_least_as_severe_as_get_level(at_least_as_severe_as, &_level);
+       ok(status == LTTNG_LOG_LEVEL_RULE_STATUS_OK, "Get the level");
+       ok(_level == level, "Level property is valid");
+
+       test_log_level_rule_is_equal_at_least_as_severe_as();
+       test_log_level_rule_serialize_deserialize(at_least_as_severe_as);
+       lttng_log_level_rule_destroy(at_least_as_severe_as);
+}
+
+int main(int argc, const char *argv[])
+{
+       plan_tests(NUM_TESTS);
+       test_log_level_rule_exactly();
+       test_log_level_rule_at_least_as_severe_as();
+       test_log_level_rule_error();
+       return exit_status();
+}
diff --git a/tests/unit/test_notification.c b/tests/unit/test_notification.c
deleted file mode 100644 (file)
index a44c8ef..0000000
+++ /dev/null
@@ -1,313 +0,0 @@
-/*
- * test_notification.c
- *
- * Unit tests for the notification API.
- *
- * Copyright (C) 2017 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
- *
- * SPDX-License-Identifier: MIT
- *
- */
-
-#include <inttypes.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <tap/tap.h>
-
-#include <lttng/action/action.h>
-#include <lttng/action/notify.h>
-#include <lttng/condition/buffer-usage.h>
-#include <lttng/condition/condition.h>
-#include <lttng/domain.h>
-#include <lttng/notification/notification.h>
-#include <lttng/trigger/trigger.h>
-
-#include <common/macros.h>
-
-/* For error.h */
-int lttng_opt_quiet = 1;
-int lttng_opt_verbose;
-int lttng_opt_mi;
-
-#define NUM_TESTS 180
-
-static void test_condition_buffer_usage(
-               struct lttng_condition *buffer_usage_condition)
-{
-       enum lttng_condition_status status = LTTNG_CONDITION_STATUS_OK;
-       const char *session_name = NULL;
-       const char *channel_name = NULL;
-       enum lttng_domain_type domain_type;
-       /* Start at a non zero value to validate initialization */
-       double threshold_ratio;
-       uint64_t threshold_bytes;
-
-       LTTNG_ASSERT(buffer_usage_condition);
-
-       diag("Validating initialization");
-       status = lttng_condition_buffer_usage_get_threshold_ratio(buffer_usage_condition, &threshold_ratio);
-       ok(status == LTTNG_CONDITION_STATUS_UNSET, "Threshold ratio is unset");
-
-       status = lttng_condition_buffer_usage_get_threshold(buffer_usage_condition, &threshold_bytes);
-       ok(status == LTTNG_CONDITION_STATUS_UNSET, "Threshold byte is unset");
-
-       status = lttng_condition_buffer_usage_get_session_name(buffer_usage_condition, &session_name);
-       ok(status == LTTNG_CONDITION_STATUS_UNSET, "Session name is unset");
-       ok(!session_name, "Session name is null");
-
-       status = lttng_condition_buffer_usage_get_channel_name(buffer_usage_condition, &channel_name);
-       ok(status == LTTNG_CONDITION_STATUS_UNSET, "Channel name is unset");
-       ok(!session_name, "Channel name is null");
-
-       status = lttng_condition_buffer_usage_get_domain_type(buffer_usage_condition, &domain_type);
-       ok(status == LTTNG_CONDITION_STATUS_UNSET, "Domain name is unset");
-
-       diag("Testing session name set/get");
-       status = lttng_condition_buffer_usage_set_session_name(NULL, "Test");
-       ok(status == LTTNG_CONDITION_STATUS_INVALID, "Set null condition on set session name");
-       status = lttng_condition_buffer_usage_get_session_name(NULL, &session_name);
-       ok(status == LTTNG_CONDITION_STATUS_INVALID, "Get session name with null condition");
-       ok(!session_name, "Session name is null");
-       status = lttng_condition_buffer_usage_get_session_name(buffer_usage_condition, &session_name);
-       ok(status == LTTNG_CONDITION_STATUS_UNSET, "Session name is unset");
-       ok(!session_name, "Session name is null");
-
-       status = lttng_condition_buffer_usage_set_session_name(buffer_usage_condition, NULL);
-       ok(status == LTTNG_CONDITION_STATUS_INVALID, "Set null session name");
-       status = lttng_condition_buffer_usage_get_session_name(buffer_usage_condition, &session_name);
-       ok(status == LTTNG_CONDITION_STATUS_UNSET, "Session name is unset");
-       ok(!session_name, "Session name is null");
-
-       status = lttng_condition_buffer_usage_set_session_name(buffer_usage_condition, "");
-       ok(status == LTTNG_CONDITION_STATUS_INVALID, "Set empty session name");
-       status = lttng_condition_buffer_usage_get_session_name(buffer_usage_condition, &session_name);
-       ok(status == LTTNG_CONDITION_STATUS_UNSET, "Session name is unset");
-       ok(!session_name, "Session name is null");
-
-       status = lttng_condition_buffer_usage_set_session_name(buffer_usage_condition, "session420");
-       ok(status == LTTNG_CONDITION_STATUS_OK, "Set session name session420");
-       status = lttng_condition_buffer_usage_get_session_name(buffer_usage_condition, &session_name);
-       ok(status == LTTNG_CONDITION_STATUS_OK, "Session name is set");
-       ok(session_name, "Session name has a value");
-       ok(strcmp("session420", session_name) == 0, "Session name is %s", "session420");
-
-       /*
-        * Test second set on session_name. Test invalid set and validate that
-        * the value is still the previous good one.
-        */
-
-       status = lttng_condition_buffer_usage_set_session_name(buffer_usage_condition, "");
-       ok(status == LTTNG_CONDITION_STATUS_INVALID, "Set session name to empty");
-       status = lttng_condition_buffer_usage_get_session_name(buffer_usage_condition, &session_name);
-       ok(status == LTTNG_CONDITION_STATUS_OK, "Session name is still set");
-       ok(session_name, "Session name has a value");
-       ok(strcmp("session420", session_name) == 0, "Session is still name is %s", "session420");
-
-       diag("Testing channel name set/get");
-       status = lttng_condition_buffer_usage_set_channel_name(NULL, "Test");
-       ok(status == LTTNG_CONDITION_STATUS_INVALID, "Set null condition on set channel name");
-       status = lttng_condition_buffer_usage_get_channel_name(NULL, &channel_name);
-       ok(status == LTTNG_CONDITION_STATUS_INVALID, "Get channel name with null condition");
-       status = lttng_condition_buffer_usage_get_channel_name(buffer_usage_condition, &channel_name);
-       ok(status == LTTNG_CONDITION_STATUS_UNSET, "Channel name is unset");
-       ok(!channel_name, "Channel name is null");
-
-       status = lttng_condition_buffer_usage_set_channel_name(buffer_usage_condition, NULL);
-       ok(status == LTTNG_CONDITION_STATUS_INVALID, "Set null channel name");
-       status = lttng_condition_buffer_usage_get_channel_name(buffer_usage_condition, &channel_name);
-       ok(status == LTTNG_CONDITION_STATUS_UNSET, "Channel name is unset");
-       ok(!channel_name, "Channel name is null");
-
-       status = lttng_condition_buffer_usage_set_channel_name(buffer_usage_condition, "");
-       ok(status == LTTNG_CONDITION_STATUS_INVALID, "Set empty channel name");
-       status = lttng_condition_buffer_usage_get_channel_name(buffer_usage_condition, &channel_name);
-       ok(status == LTTNG_CONDITION_STATUS_UNSET, "Channel name is unset");
-       ok(!channel_name, "Channel name is null");
-
-       status = lttng_condition_buffer_usage_set_channel_name(buffer_usage_condition, "channel420");
-       ok(status == LTTNG_CONDITION_STATUS_OK, "Set channel name channel420");
-       status = lttng_condition_buffer_usage_get_channel_name(buffer_usage_condition, &channel_name);
-       ok(status == LTTNG_CONDITION_STATUS_OK, "Channel name is set");
-       ok(channel_name, "Channel name has a value");
-       ok(strcmp("channel420", channel_name) == 0, "Channel name is %s", "channel420");
-
-       /*
-        * Test second set on channel_name. Test invalid set and validate that
-        * the value is still the previous good one.
-        */
-
-       status = lttng_condition_buffer_usage_set_channel_name(buffer_usage_condition, "");
-       ok(status == LTTNG_CONDITION_STATUS_INVALID, "Set channel name to empty");
-       status = lttng_condition_buffer_usage_get_channel_name(buffer_usage_condition, &channel_name);
-       ok(status == LTTNG_CONDITION_STATUS_OK, "Channel name is still set");
-       ok(channel_name, "Channel name has a value");
-       ok(strcmp("channel420", channel_name) == 0, "Channel is still name is %s", "channel420");
-
-       diag("Testing threshold ratio set/get");
-       status = lttng_condition_buffer_usage_set_threshold_ratio(NULL, 0.420);
-       ok(status == LTTNG_CONDITION_STATUS_INVALID, "Set threshold ratio with null condition");
-       status = lttng_condition_buffer_usage_get_threshold_ratio(NULL, &threshold_ratio);
-       ok(status == LTTNG_CONDITION_STATUS_INVALID, "Get threshold ratio with null condition");
-       status = lttng_condition_buffer_usage_get_threshold_ratio(buffer_usage_condition, &threshold_ratio);
-       ok(status == LTTNG_CONDITION_STATUS_UNSET, "Threshold ratio is unset");
-
-       status = lttng_condition_buffer_usage_set_threshold_ratio(buffer_usage_condition, -100.0);
-       ok(status == LTTNG_CONDITION_STATUS_INVALID, "Set threshold ratio < 0");
-       status = lttng_condition_buffer_usage_get_threshold_ratio(buffer_usage_condition, &threshold_ratio);
-       ok(status == LTTNG_CONDITION_STATUS_UNSET, "Threshold ratio is unset");
-
-       status = lttng_condition_buffer_usage_set_threshold_ratio(buffer_usage_condition, 200.0);
-       ok(status == LTTNG_CONDITION_STATUS_INVALID, "Set Threshold ratio > 1");
-       status = lttng_condition_buffer_usage_get_threshold_ratio(buffer_usage_condition, &threshold_ratio);
-       ok(status == LTTNG_CONDITION_STATUS_UNSET, "Threshold ratio is unset");
-
-       status = lttng_condition_buffer_usage_set_threshold_ratio(buffer_usage_condition, 1.0);
-       ok(status == LTTNG_CONDITION_STATUS_OK, "Set threshold ratio == 1.0");
-       status = lttng_condition_buffer_usage_get_threshold_ratio(buffer_usage_condition, &threshold_ratio);
-       ok(status == LTTNG_CONDITION_STATUS_OK, "Threshold ratio is set");
-       ok(threshold_ratio == 1.0, "Threshold ratio is 1.0");
-
-       status = lttng_condition_buffer_usage_set_threshold_ratio(buffer_usage_condition, 0.0);
-       ok(status == LTTNG_CONDITION_STATUS_OK, "Set threshold ratio == 0.0");
-       status = lttng_condition_buffer_usage_get_threshold_ratio(buffer_usage_condition, &threshold_ratio);
-       ok(status == LTTNG_CONDITION_STATUS_OK, "Threshold ratio is set");
-       ok(threshold_ratio == 0.0, "Threshold ratio is 0.0");
-
-       status = lttng_condition_buffer_usage_set_threshold_ratio(buffer_usage_condition, 0.420);
-       ok(status == LTTNG_CONDITION_STATUS_OK, "Set threshold ratio == 0.420");
-       status = lttng_condition_buffer_usage_get_threshold_ratio(buffer_usage_condition, &threshold_ratio);
-       ok(status == LTTNG_CONDITION_STATUS_OK, "Threshold ratio is set");
-       ok(threshold_ratio == 0.420, "Threshold ratio is 0.420");
-
-       diag("Testing threshold bytes set/get");
-       status = lttng_condition_buffer_usage_set_threshold(NULL, 100000);
-       ok(status == LTTNG_CONDITION_STATUS_INVALID, "Set threshold with null condition");
-       status = lttng_condition_buffer_usage_get_threshold(NULL, &threshold_bytes);
-       ok(status == LTTNG_CONDITION_STATUS_INVALID, "Get threshold value with null condition ");
-       status = lttng_condition_buffer_usage_get_threshold(buffer_usage_condition, &threshold_bytes);
-       ok(status == LTTNG_CONDITION_STATUS_UNSET, "Threshold is unset");
-
-       status = lttng_condition_buffer_usage_set_threshold(buffer_usage_condition, 100000);
-       ok(status == LTTNG_CONDITION_STATUS_OK, "Set threshold > 0");
-       status = lttng_condition_buffer_usage_get_threshold(buffer_usage_condition, &threshold_bytes);
-       ok(status == LTTNG_CONDITION_STATUS_OK, "Threshold is set");
-       ok(threshold_bytes == 100000, "Threshold is %" PRIu64 , 100000);
-
-       status = lttng_condition_buffer_usage_set_threshold(buffer_usage_condition, UINT64_MAX);
-       ok(status == LTTNG_CONDITION_STATUS_OK, "Set threshold UINT64_MAX");
-       status = lttng_condition_buffer_usage_get_threshold(buffer_usage_condition, &threshold_bytes);
-       ok(status == LTTNG_CONDITION_STATUS_OK, "Threshold is set");
-       ok(threshold_bytes == UINT64_MAX, "Threshold is UINT64_MAX");
-
-       status = lttng_condition_buffer_usage_set_threshold(buffer_usage_condition, 0);
-       ok(status == LTTNG_CONDITION_STATUS_OK, "Set threshold  == 0");
-       status = lttng_condition_buffer_usage_get_threshold(buffer_usage_condition, &threshold_bytes);
-       ok(status == LTTNG_CONDITION_STATUS_OK, "Threshold is set");
-       ok(threshold_bytes == 0, "Threshold is %d", 0);
-
-       /*
-        * Test value of threshold ration, since we overwrote it with a byte
-        * threshold. Make sure it gets squashed.
-        */
-       diag("Testing interaction between byte and ratio thresholds");
-
-       threshold_ratio = -1.0;
-       status = lttng_condition_buffer_usage_get_threshold_ratio(buffer_usage_condition, &threshold_ratio);
-       ok(status == LTTNG_CONDITION_STATUS_UNSET, "Threshold ratio is unset");
-       ok(threshold_ratio == -1.0, "Threshold ratio is untouched");
-
-       /* Set a ratio to validate that the byte threshold is now unset */
-       status = lttng_condition_buffer_usage_set_threshold_ratio(buffer_usage_condition, 0.420);
-       ok(status == LTTNG_CONDITION_STATUS_OK, "Set threshold ratio == 0.420");
-       status = lttng_condition_buffer_usage_get_threshold_ratio(buffer_usage_condition, &threshold_ratio);
-       ok(status == LTTNG_CONDITION_STATUS_OK, "Threshold ratio is set");
-       ok(threshold_ratio == 0.420, "Threshold ratio is 0.420");
-
-       threshold_bytes = 420;
-       status = lttng_condition_buffer_usage_get_threshold(buffer_usage_condition, &threshold_bytes);
-       ok(status == LTTNG_CONDITION_STATUS_UNSET, "Threshold is unset");
-       ok(threshold_bytes == 420, "Threshold is untouched");
-
-       diag("Testing domain type set/get");
-       status = lttng_condition_buffer_usage_set_domain_type(NULL, LTTNG_DOMAIN_UST);
-       ok(status == LTTNG_CONDITION_STATUS_INVALID, "Set domain type with null condition");
-       status = lttng_condition_buffer_usage_get_domain_type(NULL, &domain_type);
-       ok(status == LTTNG_CONDITION_STATUS_INVALID, "Get domain type with null condition");
-
-       status = lttng_condition_buffer_usage_set_domain_type(buffer_usage_condition, LTTNG_DOMAIN_NONE);
-       ok(status == LTTNG_CONDITION_STATUS_INVALID, "Set domain type as LTTNG_DOMAIN_NONE");
-       status = lttng_condition_buffer_usage_get_domain_type(buffer_usage_condition, &domain_type);
-       ok(status == LTTNG_CONDITION_STATUS_UNSET, "Domain type is unset");
-
-       status = lttng_condition_buffer_usage_set_domain_type(buffer_usage_condition, LTTNG_DOMAIN_UST);
-       ok(status == LTTNG_CONDITION_STATUS_OK, "Set domain type as LTTNG_DOMAIN_UST");
-       status = lttng_condition_buffer_usage_get_domain_type(buffer_usage_condition, &domain_type);
-       ok(status == LTTNG_CONDITION_STATUS_OK, "Domain type is set");
-       ok(domain_type == LTTNG_DOMAIN_UST, "Domain type is LTTNG_DOMAIN_UST");
-}
-
-static void test_condition_buffer_usage_low(void)
-{
-       struct lttng_condition *buffer_usage_low = NULL;
-
-       diag("Testing lttng_condition_buffer_usage_low_create");
-       buffer_usage_low = lttng_condition_buffer_usage_low_create();
-       ok(buffer_usage_low, "Condition allocated");
-
-       ok(lttng_condition_get_type(buffer_usage_low) == LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW, "Condition is of type \"low buffer usage\"");
-
-       test_condition_buffer_usage(buffer_usage_low);
-
-       lttng_condition_destroy(buffer_usage_low);
-}
-
-static void test_condition_buffer_usage_high(void)
-{
-       struct lttng_condition *buffer_usage_high = NULL;
-
-       diag("Testing lttng_condition_buffer_usage_high_create");
-       buffer_usage_high = lttng_condition_buffer_usage_high_create();
-       ok(buffer_usage_high, "High buffer usage condition allocated");
-
-       ok(lttng_condition_get_type(buffer_usage_high) == LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH, "Condition is of type \"high buffer usage\"");
-
-       test_condition_buffer_usage(buffer_usage_high);
-
-       lttng_condition_destroy(buffer_usage_high);
-}
-
-static void test_trigger(void)
-{
-       struct lttng_action *notify_action = NULL;
-       struct lttng_condition *buffer_usage_high = NULL;
-       struct lttng_trigger *trigger = NULL;
-
-       notify_action = lttng_action_notify_create();
-       buffer_usage_high = lttng_condition_buffer_usage_high_create();
-
-       trigger = lttng_trigger_create(NULL, NULL);
-       ok(!trigger, "lttng_trigger_create(NULL, NULL) returns null");
-       trigger = lttng_trigger_create(buffer_usage_high, NULL);
-       ok(!trigger, "lttng_trigger_create(NON-NULL, NULL) returns null");
-       trigger = lttng_trigger_create(NULL, notify_action);
-       ok(!trigger, "lttng_trigger_create(NULL, NON-NULL) returns null");
-
-       trigger = lttng_trigger_create(buffer_usage_high, notify_action);
-       ok(trigger, "lttng_trigger_create(NON-NULL, NON-NULL) returns an object");
-
-       lttng_action_destroy(notify_action);
-       lttng_condition_destroy(buffer_usage_high);
-       lttng_trigger_destroy(trigger);
-}
-
-
-int main(int argc, const char *argv[])
-{
-       plan_tests(NUM_TESTS);
-       test_condition_buffer_usage_low();
-       test_condition_buffer_usage_high();
-       test_trigger();
-       return exit_status();
-}
diff --git a/tests/unit/test_notification.cpp b/tests/unit/test_notification.cpp
new file mode 100644 (file)
index 0000000..a44c8ef
--- /dev/null
@@ -0,0 +1,313 @@
+/*
+ * test_notification.c
+ *
+ * Unit tests for the notification API.
+ *
+ * Copyright (C) 2017 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ */
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <tap/tap.h>
+
+#include <lttng/action/action.h>
+#include <lttng/action/notify.h>
+#include <lttng/condition/buffer-usage.h>
+#include <lttng/condition/condition.h>
+#include <lttng/domain.h>
+#include <lttng/notification/notification.h>
+#include <lttng/trigger/trigger.h>
+
+#include <common/macros.h>
+
+/* For error.h */
+int lttng_opt_quiet = 1;
+int lttng_opt_verbose;
+int lttng_opt_mi;
+
+#define NUM_TESTS 180
+
+static void test_condition_buffer_usage(
+               struct lttng_condition *buffer_usage_condition)
+{
+       enum lttng_condition_status status = LTTNG_CONDITION_STATUS_OK;
+       const char *session_name = NULL;
+       const char *channel_name = NULL;
+       enum lttng_domain_type domain_type;
+       /* Start at a non zero value to validate initialization */
+       double threshold_ratio;
+       uint64_t threshold_bytes;
+
+       LTTNG_ASSERT(buffer_usage_condition);
+
+       diag("Validating initialization");
+       status = lttng_condition_buffer_usage_get_threshold_ratio(buffer_usage_condition, &threshold_ratio);
+       ok(status == LTTNG_CONDITION_STATUS_UNSET, "Threshold ratio is unset");
+
+       status = lttng_condition_buffer_usage_get_threshold(buffer_usage_condition, &threshold_bytes);
+       ok(status == LTTNG_CONDITION_STATUS_UNSET, "Threshold byte is unset");
+
+       status = lttng_condition_buffer_usage_get_session_name(buffer_usage_condition, &session_name);
+       ok(status == LTTNG_CONDITION_STATUS_UNSET, "Session name is unset");
+       ok(!session_name, "Session name is null");
+
+       status = lttng_condition_buffer_usage_get_channel_name(buffer_usage_condition, &channel_name);
+       ok(status == LTTNG_CONDITION_STATUS_UNSET, "Channel name is unset");
+       ok(!session_name, "Channel name is null");
+
+       status = lttng_condition_buffer_usage_get_domain_type(buffer_usage_condition, &domain_type);
+       ok(status == LTTNG_CONDITION_STATUS_UNSET, "Domain name is unset");
+
+       diag("Testing session name set/get");
+       status = lttng_condition_buffer_usage_set_session_name(NULL, "Test");
+       ok(status == LTTNG_CONDITION_STATUS_INVALID, "Set null condition on set session name");
+       status = lttng_condition_buffer_usage_get_session_name(NULL, &session_name);
+       ok(status == LTTNG_CONDITION_STATUS_INVALID, "Get session name with null condition");
+       ok(!session_name, "Session name is null");
+       status = lttng_condition_buffer_usage_get_session_name(buffer_usage_condition, &session_name);
+       ok(status == LTTNG_CONDITION_STATUS_UNSET, "Session name is unset");
+       ok(!session_name, "Session name is null");
+
+       status = lttng_condition_buffer_usage_set_session_name(buffer_usage_condition, NULL);
+       ok(status == LTTNG_CONDITION_STATUS_INVALID, "Set null session name");
+       status = lttng_condition_buffer_usage_get_session_name(buffer_usage_condition, &session_name);
+       ok(status == LTTNG_CONDITION_STATUS_UNSET, "Session name is unset");
+       ok(!session_name, "Session name is null");
+
+       status = lttng_condition_buffer_usage_set_session_name(buffer_usage_condition, "");
+       ok(status == LTTNG_CONDITION_STATUS_INVALID, "Set empty session name");
+       status = lttng_condition_buffer_usage_get_session_name(buffer_usage_condition, &session_name);
+       ok(status == LTTNG_CONDITION_STATUS_UNSET, "Session name is unset");
+       ok(!session_name, "Session name is null");
+
+       status = lttng_condition_buffer_usage_set_session_name(buffer_usage_condition, "session420");
+       ok(status == LTTNG_CONDITION_STATUS_OK, "Set session name session420");
+       status = lttng_condition_buffer_usage_get_session_name(buffer_usage_condition, &session_name);
+       ok(status == LTTNG_CONDITION_STATUS_OK, "Session name is set");
+       ok(session_name, "Session name has a value");
+       ok(strcmp("session420", session_name) == 0, "Session name is %s", "session420");
+
+       /*
+        * Test second set on session_name. Test invalid set and validate that
+        * the value is still the previous good one.
+        */
+
+       status = lttng_condition_buffer_usage_set_session_name(buffer_usage_condition, "");
+       ok(status == LTTNG_CONDITION_STATUS_INVALID, "Set session name to empty");
+       status = lttng_condition_buffer_usage_get_session_name(buffer_usage_condition, &session_name);
+       ok(status == LTTNG_CONDITION_STATUS_OK, "Session name is still set");
+       ok(session_name, "Session name has a value");
+       ok(strcmp("session420", session_name) == 0, "Session is still name is %s", "session420");
+
+       diag("Testing channel name set/get");
+       status = lttng_condition_buffer_usage_set_channel_name(NULL, "Test");
+       ok(status == LTTNG_CONDITION_STATUS_INVALID, "Set null condition on set channel name");
+       status = lttng_condition_buffer_usage_get_channel_name(NULL, &channel_name);
+       ok(status == LTTNG_CONDITION_STATUS_INVALID, "Get channel name with null condition");
+       status = lttng_condition_buffer_usage_get_channel_name(buffer_usage_condition, &channel_name);
+       ok(status == LTTNG_CONDITION_STATUS_UNSET, "Channel name is unset");
+       ok(!channel_name, "Channel name is null");
+
+       status = lttng_condition_buffer_usage_set_channel_name(buffer_usage_condition, NULL);
+       ok(status == LTTNG_CONDITION_STATUS_INVALID, "Set null channel name");
+       status = lttng_condition_buffer_usage_get_channel_name(buffer_usage_condition, &channel_name);
+       ok(status == LTTNG_CONDITION_STATUS_UNSET, "Channel name is unset");
+       ok(!channel_name, "Channel name is null");
+
+       status = lttng_condition_buffer_usage_set_channel_name(buffer_usage_condition, "");
+       ok(status == LTTNG_CONDITION_STATUS_INVALID, "Set empty channel name");
+       status = lttng_condition_buffer_usage_get_channel_name(buffer_usage_condition, &channel_name);
+       ok(status == LTTNG_CONDITION_STATUS_UNSET, "Channel name is unset");
+       ok(!channel_name, "Channel name is null");
+
+       status = lttng_condition_buffer_usage_set_channel_name(buffer_usage_condition, "channel420");
+       ok(status == LTTNG_CONDITION_STATUS_OK, "Set channel name channel420");
+       status = lttng_condition_buffer_usage_get_channel_name(buffer_usage_condition, &channel_name);
+       ok(status == LTTNG_CONDITION_STATUS_OK, "Channel name is set");
+       ok(channel_name, "Channel name has a value");
+       ok(strcmp("channel420", channel_name) == 0, "Channel name is %s", "channel420");
+
+       /*
+        * Test second set on channel_name. Test invalid set and validate that
+        * the value is still the previous good one.
+        */
+
+       status = lttng_condition_buffer_usage_set_channel_name(buffer_usage_condition, "");
+       ok(status == LTTNG_CONDITION_STATUS_INVALID, "Set channel name to empty");
+       status = lttng_condition_buffer_usage_get_channel_name(buffer_usage_condition, &channel_name);
+       ok(status == LTTNG_CONDITION_STATUS_OK, "Channel name is still set");
+       ok(channel_name, "Channel name has a value");
+       ok(strcmp("channel420", channel_name) == 0, "Channel is still name is %s", "channel420");
+
+       diag("Testing threshold ratio set/get");
+       status = lttng_condition_buffer_usage_set_threshold_ratio(NULL, 0.420);
+       ok(status == LTTNG_CONDITION_STATUS_INVALID, "Set threshold ratio with null condition");
+       status = lttng_condition_buffer_usage_get_threshold_ratio(NULL, &threshold_ratio);
+       ok(status == LTTNG_CONDITION_STATUS_INVALID, "Get threshold ratio with null condition");
+       status = lttng_condition_buffer_usage_get_threshold_ratio(buffer_usage_condition, &threshold_ratio);
+       ok(status == LTTNG_CONDITION_STATUS_UNSET, "Threshold ratio is unset");
+
+       status = lttng_condition_buffer_usage_set_threshold_ratio(buffer_usage_condition, -100.0);
+       ok(status == LTTNG_CONDITION_STATUS_INVALID, "Set threshold ratio < 0");
+       status = lttng_condition_buffer_usage_get_threshold_ratio(buffer_usage_condition, &threshold_ratio);
+       ok(status == LTTNG_CONDITION_STATUS_UNSET, "Threshold ratio is unset");
+
+       status = lttng_condition_buffer_usage_set_threshold_ratio(buffer_usage_condition, 200.0);
+       ok(status == LTTNG_CONDITION_STATUS_INVALID, "Set Threshold ratio > 1");
+       status = lttng_condition_buffer_usage_get_threshold_ratio(buffer_usage_condition, &threshold_ratio);
+       ok(status == LTTNG_CONDITION_STATUS_UNSET, "Threshold ratio is unset");
+
+       status = lttng_condition_buffer_usage_set_threshold_ratio(buffer_usage_condition, 1.0);
+       ok(status == LTTNG_CONDITION_STATUS_OK, "Set threshold ratio == 1.0");
+       status = lttng_condition_buffer_usage_get_threshold_ratio(buffer_usage_condition, &threshold_ratio);
+       ok(status == LTTNG_CONDITION_STATUS_OK, "Threshold ratio is set");
+       ok(threshold_ratio == 1.0, "Threshold ratio is 1.0");
+
+       status = lttng_condition_buffer_usage_set_threshold_ratio(buffer_usage_condition, 0.0);
+       ok(status == LTTNG_CONDITION_STATUS_OK, "Set threshold ratio == 0.0");
+       status = lttng_condition_buffer_usage_get_threshold_ratio(buffer_usage_condition, &threshold_ratio);
+       ok(status == LTTNG_CONDITION_STATUS_OK, "Threshold ratio is set");
+       ok(threshold_ratio == 0.0, "Threshold ratio is 0.0");
+
+       status = lttng_condition_buffer_usage_set_threshold_ratio(buffer_usage_condition, 0.420);
+       ok(status == LTTNG_CONDITION_STATUS_OK, "Set threshold ratio == 0.420");
+       status = lttng_condition_buffer_usage_get_threshold_ratio(buffer_usage_condition, &threshold_ratio);
+       ok(status == LTTNG_CONDITION_STATUS_OK, "Threshold ratio is set");
+       ok(threshold_ratio == 0.420, "Threshold ratio is 0.420");
+
+       diag("Testing threshold bytes set/get");
+       status = lttng_condition_buffer_usage_set_threshold(NULL, 100000);
+       ok(status == LTTNG_CONDITION_STATUS_INVALID, "Set threshold with null condition");
+       status = lttng_condition_buffer_usage_get_threshold(NULL, &threshold_bytes);
+       ok(status == LTTNG_CONDITION_STATUS_INVALID, "Get threshold value with null condition ");
+       status = lttng_condition_buffer_usage_get_threshold(buffer_usage_condition, &threshold_bytes);
+       ok(status == LTTNG_CONDITION_STATUS_UNSET, "Threshold is unset");
+
+       status = lttng_condition_buffer_usage_set_threshold(buffer_usage_condition, 100000);
+       ok(status == LTTNG_CONDITION_STATUS_OK, "Set threshold > 0");
+       status = lttng_condition_buffer_usage_get_threshold(buffer_usage_condition, &threshold_bytes);
+       ok(status == LTTNG_CONDITION_STATUS_OK, "Threshold is set");
+       ok(threshold_bytes == 100000, "Threshold is %" PRIu64 , 100000);
+
+       status = lttng_condition_buffer_usage_set_threshold(buffer_usage_condition, UINT64_MAX);
+       ok(status == LTTNG_CONDITION_STATUS_OK, "Set threshold UINT64_MAX");
+       status = lttng_condition_buffer_usage_get_threshold(buffer_usage_condition, &threshold_bytes);
+       ok(status == LTTNG_CONDITION_STATUS_OK, "Threshold is set");
+       ok(threshold_bytes == UINT64_MAX, "Threshold is UINT64_MAX");
+
+       status = lttng_condition_buffer_usage_set_threshold(buffer_usage_condition, 0);
+       ok(status == LTTNG_CONDITION_STATUS_OK, "Set threshold  == 0");
+       status = lttng_condition_buffer_usage_get_threshold(buffer_usage_condition, &threshold_bytes);
+       ok(status == LTTNG_CONDITION_STATUS_OK, "Threshold is set");
+       ok(threshold_bytes == 0, "Threshold is %d", 0);
+
+       /*
+        * Test value of threshold ration, since we overwrote it with a byte
+        * threshold. Make sure it gets squashed.
+        */
+       diag("Testing interaction between byte and ratio thresholds");
+
+       threshold_ratio = -1.0;
+       status = lttng_condition_buffer_usage_get_threshold_ratio(buffer_usage_condition, &threshold_ratio);
+       ok(status == LTTNG_CONDITION_STATUS_UNSET, "Threshold ratio is unset");
+       ok(threshold_ratio == -1.0, "Threshold ratio is untouched");
+
+       /* Set a ratio to validate that the byte threshold is now unset */
+       status = lttng_condition_buffer_usage_set_threshold_ratio(buffer_usage_condition, 0.420);
+       ok(status == LTTNG_CONDITION_STATUS_OK, "Set threshold ratio == 0.420");
+       status = lttng_condition_buffer_usage_get_threshold_ratio(buffer_usage_condition, &threshold_ratio);
+       ok(status == LTTNG_CONDITION_STATUS_OK, "Threshold ratio is set");
+       ok(threshold_ratio == 0.420, "Threshold ratio is 0.420");
+
+       threshold_bytes = 420;
+       status = lttng_condition_buffer_usage_get_threshold(buffer_usage_condition, &threshold_bytes);
+       ok(status == LTTNG_CONDITION_STATUS_UNSET, "Threshold is unset");
+       ok(threshold_bytes == 420, "Threshold is untouched");
+
+       diag("Testing domain type set/get");
+       status = lttng_condition_buffer_usage_set_domain_type(NULL, LTTNG_DOMAIN_UST);
+       ok(status == LTTNG_CONDITION_STATUS_INVALID, "Set domain type with null condition");
+       status = lttng_condition_buffer_usage_get_domain_type(NULL, &domain_type);
+       ok(status == LTTNG_CONDITION_STATUS_INVALID, "Get domain type with null condition");
+
+       status = lttng_condition_buffer_usage_set_domain_type(buffer_usage_condition, LTTNG_DOMAIN_NONE);
+       ok(status == LTTNG_CONDITION_STATUS_INVALID, "Set domain type as LTTNG_DOMAIN_NONE");
+       status = lttng_condition_buffer_usage_get_domain_type(buffer_usage_condition, &domain_type);
+       ok(status == LTTNG_CONDITION_STATUS_UNSET, "Domain type is unset");
+
+       status = lttng_condition_buffer_usage_set_domain_type(buffer_usage_condition, LTTNG_DOMAIN_UST);
+       ok(status == LTTNG_CONDITION_STATUS_OK, "Set domain type as LTTNG_DOMAIN_UST");
+       status = lttng_condition_buffer_usage_get_domain_type(buffer_usage_condition, &domain_type);
+       ok(status == LTTNG_CONDITION_STATUS_OK, "Domain type is set");
+       ok(domain_type == LTTNG_DOMAIN_UST, "Domain type is LTTNG_DOMAIN_UST");
+}
+
+static void test_condition_buffer_usage_low(void)
+{
+       struct lttng_condition *buffer_usage_low = NULL;
+
+       diag("Testing lttng_condition_buffer_usage_low_create");
+       buffer_usage_low = lttng_condition_buffer_usage_low_create();
+       ok(buffer_usage_low, "Condition allocated");
+
+       ok(lttng_condition_get_type(buffer_usage_low) == LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW, "Condition is of type \"low buffer usage\"");
+
+       test_condition_buffer_usage(buffer_usage_low);
+
+       lttng_condition_destroy(buffer_usage_low);
+}
+
+static void test_condition_buffer_usage_high(void)
+{
+       struct lttng_condition *buffer_usage_high = NULL;
+
+       diag("Testing lttng_condition_buffer_usage_high_create");
+       buffer_usage_high = lttng_condition_buffer_usage_high_create();
+       ok(buffer_usage_high, "High buffer usage condition allocated");
+
+       ok(lttng_condition_get_type(buffer_usage_high) == LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH, "Condition is of type \"high buffer usage\"");
+
+       test_condition_buffer_usage(buffer_usage_high);
+
+       lttng_condition_destroy(buffer_usage_high);
+}
+
+static void test_trigger(void)
+{
+       struct lttng_action *notify_action = NULL;
+       struct lttng_condition *buffer_usage_high = NULL;
+       struct lttng_trigger *trigger = NULL;
+
+       notify_action = lttng_action_notify_create();
+       buffer_usage_high = lttng_condition_buffer_usage_high_create();
+
+       trigger = lttng_trigger_create(NULL, NULL);
+       ok(!trigger, "lttng_trigger_create(NULL, NULL) returns null");
+       trigger = lttng_trigger_create(buffer_usage_high, NULL);
+       ok(!trigger, "lttng_trigger_create(NON-NULL, NULL) returns null");
+       trigger = lttng_trigger_create(NULL, notify_action);
+       ok(!trigger, "lttng_trigger_create(NULL, NON-NULL) returns null");
+
+       trigger = lttng_trigger_create(buffer_usage_high, notify_action);
+       ok(trigger, "lttng_trigger_create(NON-NULL, NON-NULL) returns an object");
+
+       lttng_action_destroy(notify_action);
+       lttng_condition_destroy(buffer_usage_high);
+       lttng_trigger_destroy(trigger);
+}
+
+
+int main(int argc, const char *argv[])
+{
+       plan_tests(NUM_TESTS);
+       test_condition_buffer_usage_low();
+       test_condition_buffer_usage_high();
+       test_trigger();
+       return exit_status();
+}
diff --git a/tests/unit/test_payload.c b/tests/unit/test_payload.c
deleted file mode 100644 (file)
index 1c79b89..0000000
+++ /dev/null
@@ -1,240 +0,0 @@
-/*
- * Copyright (C) 2020 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- */
-
-#include <unistd.h>
-
-#include <common/compat/fcntl.h>
-#include <common/payload.h>
-#include <common/payload-view.h>
-#include <tap/tap.h>
-
-static const int TEST_COUNT = 5;
-
-/* For error.h */
-int lttng_opt_quiet = 1;
-int lttng_opt_verbose;
-int lttng_opt_mi;
-
-static void test_fd_push_pop_order(void)
-{
-       int ret, i;
-       struct lttng_payload payload;
-       int fds[3];
-
-       lttng_payload_init(&payload);
-
-       diag("Validating fd push/pop order");
-       for (i = 0; i < 3; i++) {
-               int fd = fcntl(STDOUT_FILENO, F_DUPFD, 0);
-               struct fd_handle *handle;
-
-               LTTNG_ASSERT(fd >= 0);
-               fds[i] = fd;
-
-               handle = fd_handle_create(fd);
-               LTTNG_ASSERT(handle);
-
-               ret = lttng_payload_push_fd_handle(&payload, handle);
-               fd_handle_put(handle);
-               if (ret) {
-                       break;
-               }
-       }
-
-       ok(ret == 0, "Added three file descriptors to an lttng_payload");
-
-       {
-               bool fail_pop = false;
-               struct lttng_payload_view view =
-                               lttng_payload_view_from_payload(
-                                       &payload, 0, -1);
-
-               for (i = 0; i < 3; i++) {
-                       struct fd_handle *handle =
-                                       lttng_payload_view_pop_fd_handle(&view);
-
-                       fail_pop |= fd_handle_get_fd(handle) != fds[i];
-                       fd_handle_put(handle);
-               }
-
-               ok(!fail_pop, "File descriptors are popped from a payload view in the order of insertion");
-       }
-
-       lttng_payload_reset(&payload);
-}
-
-static void test_fd_push_pop_imbalance(void)
-{
-       int ret, i;
-       struct lttng_payload payload;
-       const char * const test_description = "Error reported when popping more file descriptors than were pushed";
-
-       lttng_payload_init(&payload);
-
-       diag("Validating fd pop imbalance");
-       for (i = 0; i < 10; i++) {
-               struct fd_handle *handle;
-               int fd = fcntl(STDOUT_FILENO, F_DUPFD, 0);
-
-               LTTNG_ASSERT(fd >= 0);
-
-               handle = fd_handle_create(fd);
-               LTTNG_ASSERT(handle);
-
-               ret = lttng_payload_push_fd_handle(&payload, handle);
-               fd_handle_put(handle);
-               if (ret) {
-                       break;
-               }
-       }
-
-       {
-               struct fd_handle *handle;
-               struct lttng_payload_view view =
-                               lttng_payload_view_from_payload(
-                                       &payload, 0, -1);
-
-               for (i = 0; i < 10; i++) {
-                       handle = lttng_payload_view_pop_fd_handle(&view);
-                       fd_handle_put(handle);
-                       if (!handle) {
-                               goto fail;
-                       }
-               }
-
-               handle = lttng_payload_view_pop_fd_handle(&view);
-               ok(!handle, test_description);
-               fd_handle_put(handle);
-       }
-
-       lttng_payload_reset(&payload);
-       return;
-fail:
-       fail(test_description);
-       lttng_payload_reset(&payload);
-}
-
-static void test_fd_pop_fd_root_views(void)
-{
-       int ret, i;
-       int fd = fcntl(STDOUT_FILENO, F_DUPFD, 0);
-       struct fd_handle *handle;
-       struct lttng_payload payload;
-       const char * const test_description = "Same file descriptor returned when popping from different top-level views";
-
-       LTTNG_ASSERT(fd >= 0);
-       handle = fd_handle_create(fd);
-       LTTNG_ASSERT(handle);
-
-       lttng_payload_init(&payload);
-
-       diag("Validating root view fd pop behaviour");
-       ret = lttng_payload_push_fd_handle(&payload, handle);
-       if (ret) {
-               goto fail;
-       }
-
-       for (i = 0; i < 5; i++) {
-               int view_fd;
-               struct fd_handle *view_handle;
-               struct lttng_payload_view view =
-                               lttng_payload_view_from_payload(
-                                       &payload, 0, -1);
-
-               view_handle = lttng_payload_view_pop_fd_handle(&view);
-               if (!view_handle) {
-                       goto fail;
-               }
-
-               view_fd = fd_handle_get_fd(view_handle);
-               fd_handle_put(view_handle);
-               if (view_fd != fd || view_handle != handle) {
-                       goto fail;
-               }
-       }
-
-       lttng_payload_reset(&payload);
-       pass(test_description);
-       fd_handle_put(handle);
-       return;
-fail:
-       lttng_payload_reset(&payload);
-       fail(test_description);
-       fd_handle_put(handle);
-}
-
-static void test_fd_pop_fd_descendant_views(void)
-{
-       int ret;
-       const int fd1 = 42, fd2 = 1837;
-       struct fd_handle *handle1 = fd_handle_create(fd1);
-       struct fd_handle *handle2 = fd_handle_create(fd2);
-       struct fd_handle *view_handle1 = NULL, *view_handle2 = NULL;
-       struct lttng_payload payload;
-       const char * const test_description = "Different file descriptors returned when popping from descendant views";
-
-       lttng_payload_init(&payload);
-       LTTNG_ASSERT(handle1);
-       LTTNG_ASSERT(handle2);
-
-       diag("Validating descendant view fd pop behaviour");
-       ret = lttng_payload_push_fd_handle(&payload, handle1);
-       if (ret) {
-               goto fail;
-       }
-
-       ret = lttng_payload_push_fd_handle(&payload, handle2);
-       if (ret) {
-               goto fail;
-       }
-
-       {
-               struct lttng_payload_view view1 =
-                               lttng_payload_view_from_payload(
-                                       &payload, 0, -1);
-               struct lttng_payload_view view2 =
-                       lttng_payload_view_from_view(
-                               &view1, 0, -1);
-
-               view_handle1 = lttng_payload_view_pop_fd_handle(&view1);
-               if (!view_handle1 || fd_handle_get_fd(view_handle1) != fd1) {
-                       goto fail;
-               }
-
-               view_handle2 = lttng_payload_view_pop_fd_handle(&view2);
-               if (!view_handle2 || fd_handle_get_fd(view_handle2) != fd2) {
-                       goto fail;
-               }
-       }
-
-       lttng_payload_reset(&payload);
-       pass(test_description);
-       fd_handle_put(handle1);
-       fd_handle_put(handle2);
-       fd_handle_put(view_handle1);
-       fd_handle_put(view_handle2);
-       return;
-fail:
-       lttng_payload_reset(&payload);
-       fail(test_description);
-       fd_handle_put(handle1);
-       fd_handle_put(handle2);
-       fd_handle_put(view_handle1);
-       fd_handle_put(view_handle2);
-}
-
-int main(void)
-{
-       plan_tests(TEST_COUNT);
-
-       test_fd_push_pop_order();
-       test_fd_push_pop_imbalance();
-       test_fd_pop_fd_root_views();
-       test_fd_pop_fd_descendant_views();
-
-       return exit_status();
-}
diff --git a/tests/unit/test_payload.cpp b/tests/unit/test_payload.cpp
new file mode 100644 (file)
index 0000000..1c79b89
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2020 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#include <unistd.h>
+
+#include <common/compat/fcntl.h>
+#include <common/payload.h>
+#include <common/payload-view.h>
+#include <tap/tap.h>
+
+static const int TEST_COUNT = 5;
+
+/* For error.h */
+int lttng_opt_quiet = 1;
+int lttng_opt_verbose;
+int lttng_opt_mi;
+
+static void test_fd_push_pop_order(void)
+{
+       int ret, i;
+       struct lttng_payload payload;
+       int fds[3];
+
+       lttng_payload_init(&payload);
+
+       diag("Validating fd push/pop order");
+       for (i = 0; i < 3; i++) {
+               int fd = fcntl(STDOUT_FILENO, F_DUPFD, 0);
+               struct fd_handle *handle;
+
+               LTTNG_ASSERT(fd >= 0);
+               fds[i] = fd;
+
+               handle = fd_handle_create(fd);
+               LTTNG_ASSERT(handle);
+
+               ret = lttng_payload_push_fd_handle(&payload, handle);
+               fd_handle_put(handle);
+               if (ret) {
+                       break;
+               }
+       }
+
+       ok(ret == 0, "Added three file descriptors to an lttng_payload");
+
+       {
+               bool fail_pop = false;
+               struct lttng_payload_view view =
+                               lttng_payload_view_from_payload(
+                                       &payload, 0, -1);
+
+               for (i = 0; i < 3; i++) {
+                       struct fd_handle *handle =
+                                       lttng_payload_view_pop_fd_handle(&view);
+
+                       fail_pop |= fd_handle_get_fd(handle) != fds[i];
+                       fd_handle_put(handle);
+               }
+
+               ok(!fail_pop, "File descriptors are popped from a payload view in the order of insertion");
+       }
+
+       lttng_payload_reset(&payload);
+}
+
+static void test_fd_push_pop_imbalance(void)
+{
+       int ret, i;
+       struct lttng_payload payload;
+       const char * const test_description = "Error reported when popping more file descriptors than were pushed";
+
+       lttng_payload_init(&payload);
+
+       diag("Validating fd pop imbalance");
+       for (i = 0; i < 10; i++) {
+               struct fd_handle *handle;
+               int fd = fcntl(STDOUT_FILENO, F_DUPFD, 0);
+
+               LTTNG_ASSERT(fd >= 0);
+
+               handle = fd_handle_create(fd);
+               LTTNG_ASSERT(handle);
+
+               ret = lttng_payload_push_fd_handle(&payload, handle);
+               fd_handle_put(handle);
+               if (ret) {
+                       break;
+               }
+       }
+
+       {
+               struct fd_handle *handle;
+               struct lttng_payload_view view =
+                               lttng_payload_view_from_payload(
+                                       &payload, 0, -1);
+
+               for (i = 0; i < 10; i++) {
+                       handle = lttng_payload_view_pop_fd_handle(&view);
+                       fd_handle_put(handle);
+                       if (!handle) {
+                               goto fail;
+                       }
+               }
+
+               handle = lttng_payload_view_pop_fd_handle(&view);
+               ok(!handle, test_description);
+               fd_handle_put(handle);
+       }
+
+       lttng_payload_reset(&payload);
+       return;
+fail:
+       fail(test_description);
+       lttng_payload_reset(&payload);
+}
+
+static void test_fd_pop_fd_root_views(void)
+{
+       int ret, i;
+       int fd = fcntl(STDOUT_FILENO, F_DUPFD, 0);
+       struct fd_handle *handle;
+       struct lttng_payload payload;
+       const char * const test_description = "Same file descriptor returned when popping from different top-level views";
+
+       LTTNG_ASSERT(fd >= 0);
+       handle = fd_handle_create(fd);
+       LTTNG_ASSERT(handle);
+
+       lttng_payload_init(&payload);
+
+       diag("Validating root view fd pop behaviour");
+       ret = lttng_payload_push_fd_handle(&payload, handle);
+       if (ret) {
+               goto fail;
+       }
+
+       for (i = 0; i < 5; i++) {
+               int view_fd;
+               struct fd_handle *view_handle;
+               struct lttng_payload_view view =
+                               lttng_payload_view_from_payload(
+                                       &payload, 0, -1);
+
+               view_handle = lttng_payload_view_pop_fd_handle(&view);
+               if (!view_handle) {
+                       goto fail;
+               }
+
+               view_fd = fd_handle_get_fd(view_handle);
+               fd_handle_put(view_handle);
+               if (view_fd != fd || view_handle != handle) {
+                       goto fail;
+               }
+       }
+
+       lttng_payload_reset(&payload);
+       pass(test_description);
+       fd_handle_put(handle);
+       return;
+fail:
+       lttng_payload_reset(&payload);
+       fail(test_description);
+       fd_handle_put(handle);
+}
+
+static void test_fd_pop_fd_descendant_views(void)
+{
+       int ret;
+       const int fd1 = 42, fd2 = 1837;
+       struct fd_handle *handle1 = fd_handle_create(fd1);
+       struct fd_handle *handle2 = fd_handle_create(fd2);
+       struct fd_handle *view_handle1 = NULL, *view_handle2 = NULL;
+       struct lttng_payload payload;
+       const char * const test_description = "Different file descriptors returned when popping from descendant views";
+
+       lttng_payload_init(&payload);
+       LTTNG_ASSERT(handle1);
+       LTTNG_ASSERT(handle2);
+
+       diag("Validating descendant view fd pop behaviour");
+       ret = lttng_payload_push_fd_handle(&payload, handle1);
+       if (ret) {
+               goto fail;
+       }
+
+       ret = lttng_payload_push_fd_handle(&payload, handle2);
+       if (ret) {
+               goto fail;
+       }
+
+       {
+               struct lttng_payload_view view1 =
+                               lttng_payload_view_from_payload(
+                                       &payload, 0, -1);
+               struct lttng_payload_view view2 =
+                       lttng_payload_view_from_view(
+                               &view1, 0, -1);
+
+               view_handle1 = lttng_payload_view_pop_fd_handle(&view1);
+               if (!view_handle1 || fd_handle_get_fd(view_handle1) != fd1) {
+                       goto fail;
+               }
+
+               view_handle2 = lttng_payload_view_pop_fd_handle(&view2);
+               if (!view_handle2 || fd_handle_get_fd(view_handle2) != fd2) {
+                       goto fail;
+               }
+       }
+
+       lttng_payload_reset(&payload);
+       pass(test_description);
+       fd_handle_put(handle1);
+       fd_handle_put(handle2);
+       fd_handle_put(view_handle1);
+       fd_handle_put(view_handle2);
+       return;
+fail:
+       lttng_payload_reset(&payload);
+       fail(test_description);
+       fd_handle_put(handle1);
+       fd_handle_put(handle2);
+       fd_handle_put(view_handle1);
+       fd_handle_put(view_handle2);
+}
+
+int main(void)
+{
+       plan_tests(TEST_COUNT);
+
+       test_fd_push_pop_order();
+       test_fd_push_pop_imbalance();
+       test_fd_pop_fd_root_views();
+       test_fd_pop_fd_descendant_views();
+
+       return exit_status();
+}
diff --git a/tests/unit/test_rate_policy.c b/tests/unit/test_rate_policy.c
deleted file mode 100644 (file)
index acfe159..0000000
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
- * Unit tests for the rate policy object API.
- *
- * Copyright (C) 2019 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- */
-
-#include <inttypes.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <tap/tap.h>
-
-#include <common/payload-view.h>
-#include <common/payload.h>
-#include <lttng/action/rate-policy-internal.h>
-#include <lttng/action/rate-policy.h>
-
-/* For error.h. */
-int lttng_opt_quiet = 1;
-int lttng_opt_verbose;
-int lttng_opt_mi;
-
-#define NUM_TESTS 42
-
-static void test_rate_policy_every_n(void)
-{
-       enum lttng_rate_policy_status status;
-       struct lttng_rate_policy *policy_a = NULL; /* Interval of 100. */
-       struct lttng_rate_policy *policy_b = NULL; /* Interval of 100 */
-       struct lttng_rate_policy *policy_c = NULL; /* Interval of 1 */
-       struct lttng_rate_policy *policy_from_buffer = NULL;
-       uint64_t interval_a_b = 100;
-       uint64_t interval_c = 1;
-       uint64_t interval_query = 0;
-       struct lttng_payload payload;
-
-       lttng_payload_init(&payload);
-
-       policy_a = lttng_rate_policy_every_n_create(interval_a_b);
-       policy_b = lttng_rate_policy_every_n_create(interval_a_b);
-       policy_c = lttng_rate_policy_every_n_create(interval_c);
-       ok(policy_a != NULL,
-                       "Rate policy every n A created: interval: %" PRIu64,
-                       interval_a_b);
-       ok(policy_b != NULL,
-                       "Rate policy every n B created: interval: %" PRIu64,
-                       interval_a_b);
-       ok(policy_c != NULL,
-                       "Rate policy every n C created: interval: %" PRIu64,
-                       interval_c);
-
-       ok(LTTNG_RATE_POLICY_TYPE_EVERY_N ==
-                                       lttng_rate_policy_get_type(policy_a),
-                       "Type is LTTNG_RATE_POLICY_TYPE_EVERY_N");
-
-       /* Getter tests */
-       status = lttng_rate_policy_every_n_get_interval(NULL, NULL);
-       ok(status == LTTNG_RATE_POLICY_STATUS_INVALID,
-                       "Get interval returns INVALID");
-
-       status = lttng_rate_policy_every_n_get_interval(NULL, &interval_query);
-       ok(status == LTTNG_RATE_POLICY_STATUS_INVALID,
-                       "Get interval returns INVALID");
-
-       status = lttng_rate_policy_every_n_get_interval(policy_a, NULL);
-       ok(status == LTTNG_RATE_POLICY_STATUS_INVALID,
-                       "Get interval returns INVALID");
-
-       status = lttng_rate_policy_every_n_get_interval(
-                       policy_a, &interval_query);
-       ok(status == LTTNG_RATE_POLICY_STATUS_OK &&
-                                       interval_query == interval_a_b,
-                       " Getting interval A");
-
-       status = lttng_rate_policy_every_n_get_interval(
-                       policy_b, &interval_query);
-       ok(status == LTTNG_RATE_POLICY_STATUS_OK &&
-                                       interval_query == interval_a_b,
-                       " Getting interval B");
-
-       status = lttng_rate_policy_every_n_get_interval(
-                       policy_c, &interval_query);
-       ok(status == LTTNG_RATE_POLICY_STATUS_OK &&
-                                       interval_query == interval_c,
-                       " Getting interval C");
-
-       /* is_equal tests */
-       /* TODO: this is the behaviour introduced by the
-        * lttng_condition_is_equal back in 2017 do we want to fix this and
-        * return true if both are NULL?
-        */
-       ok(false == lttng_rate_policy_is_equal(NULL, NULL),
-                       "is equal (NULL,NULL)");
-       ok(false == lttng_rate_policy_is_equal(policy_a, NULL),
-                       "is equal (object, NULL)");
-       ok(false == lttng_rate_policy_is_equal(NULL, policy_a),
-                       " is equal (NULL, object)");
-       ok(true == lttng_rate_policy_is_equal(policy_a, policy_a),
-                       "is equal (object A, object A)");
-
-       ok(true == lttng_rate_policy_is_equal(policy_a, policy_b),
-                       "is equal (object A, object B");
-       ok(true == lttng_rate_policy_is_equal(policy_b, policy_a),
-                       "is equal (object B, object A");
-
-       ok(false == lttng_rate_policy_is_equal(policy_a, policy_c),
-                       "is equal (object A, object C)");
-       ok(false == lttng_rate_policy_is_equal(policy_c, policy_a),
-                       "is equal (object C, object A)");
-
-       /* Serialization and create_from buffer. */
-       ok(lttng_rate_policy_serialize(policy_a, &payload) == 0, "Serializing");
-       {
-               struct lttng_payload_view view =
-                               lttng_payload_view_from_payload(
-                                               &payload, 0, -1);
-
-               ok(lttng_rate_policy_create_from_payload(
-                                  &view, &policy_from_buffer) > 0 &&
-                                               policy_from_buffer != NULL,
-                               "Deserializing");
-       }
-
-       ok(lttng_rate_policy_is_equal(policy_a, policy_from_buffer),
-                       "serialized and from buffer are equal");
-
-       lttng_rate_policy_destroy(policy_a);
-       lttng_rate_policy_destroy(policy_b);
-       lttng_rate_policy_destroy(policy_c);
-       lttng_payload_reset(&payload);
-}
-
-static void test_rate_policy_once_after_n(void)
-{
-       enum lttng_rate_policy_status status;
-       struct lttng_rate_policy *policy_a = NULL; /* Threshold of 100. */
-       struct lttng_rate_policy *policy_b = NULL; /* threshold of 100 */
-       struct lttng_rate_policy *policy_c = NULL; /* threshold of 1 */
-       struct lttng_rate_policy *policy_from_buffer = NULL;
-       uint64_t threshold_a_b = 100;
-       uint64_t threshold_c = 1;
-       uint64_t threshold_query = 0;
-       struct lttng_payload payload;
-
-       lttng_payload_init(&payload);
-
-       policy_a = lttng_rate_policy_once_after_n_create(threshold_a_b);
-       policy_b = lttng_rate_policy_once_after_n_create(threshold_a_b);
-       policy_c = lttng_rate_policy_once_after_n_create(threshold_c);
-       ok(policy_a != NULL,
-                       "Rate policy every n A created: threshold: %" PRIu64,
-                       threshold_a_b);
-       ok(policy_b != NULL,
-                       "Rate policy every n B created: threshold: %" PRIu64,
-                       threshold_a_b);
-       ok(policy_c != NULL,
-                       "Rate policy every n C created: threshold: %" PRIu64,
-                       threshold_c);
-
-       ok(LTTNG_RATE_POLICY_TYPE_ONCE_AFTER_N ==
-                                       lttng_rate_policy_get_type(policy_a),
-                       "Type is LTTNG_RATE_POLICY_TYPE_once_after_n");
-
-       /* Getter tests */
-       status = lttng_rate_policy_once_after_n_get_threshold(NULL, NULL);
-       ok(status == LTTNG_RATE_POLICY_STATUS_INVALID,
-                       "Get threshold returns INVALID");
-
-       status = lttng_rate_policy_once_after_n_get_threshold(
-                       NULL, &threshold_query);
-       ok(status == LTTNG_RATE_POLICY_STATUS_INVALID,
-                       "Get threshold returns INVALID");
-
-       status = lttng_rate_policy_once_after_n_get_threshold(policy_a, NULL);
-       ok(status == LTTNG_RATE_POLICY_STATUS_INVALID,
-                       "Get threshold returns INVALID");
-
-       status = lttng_rate_policy_once_after_n_get_threshold(
-                       policy_a, &threshold_query);
-       ok(status == LTTNG_RATE_POLICY_STATUS_OK &&
-                                       threshold_query == threshold_a_b,
-                       " Getting threshold A");
-
-       status = lttng_rate_policy_once_after_n_get_threshold(
-                       policy_b, &threshold_query);
-       ok(status == LTTNG_RATE_POLICY_STATUS_OK &&
-                                       threshold_query == threshold_a_b,
-                       " Getting threshold B");
-
-       status = lttng_rate_policy_once_after_n_get_threshold(
-                       policy_c, &threshold_query);
-       ok(status == LTTNG_RATE_POLICY_STATUS_OK &&
-                                       threshold_query == threshold_c,
-                       " Getting threshold C");
-
-       /* is_equal tests */
-       /* TODO: this is the behaviour introduced by the
-        * lttng_condition_is_equal back in 2017 do we want to fix this and
-        * return true if both are NULL?
-        */
-       ok(false == lttng_rate_policy_is_equal(NULL, NULL),
-                       "is equal (NULL,NULL)");
-       ok(false == lttng_rate_policy_is_equal(policy_a, NULL),
-                       "is equal (object, NULL)");
-       ok(false == lttng_rate_policy_is_equal(NULL, policy_a),
-                       " is equal (NULL, object)");
-       ok(true == lttng_rate_policy_is_equal(policy_a, policy_a),
-                       "is equal (object A, object A)");
-
-       ok(true == lttng_rate_policy_is_equal(policy_a, policy_b),
-                       "is equal (object A, object B");
-       ok(true == lttng_rate_policy_is_equal(policy_b, policy_a),
-                       "is equal (object B, object A");
-
-       ok(false == lttng_rate_policy_is_equal(policy_a, policy_c),
-                       "is equal (object A, object C)");
-       ok(false == lttng_rate_policy_is_equal(policy_c, policy_a),
-                       "is equal (object C, object A)");
-
-       /* Serialization and create_from buffer. */
-       ok(lttng_rate_policy_serialize(policy_a, &payload) == 0, "Serializing");
-       {
-               struct lttng_payload_view view =
-                               lttng_payload_view_from_payload(
-                                               &payload, 0, -1);
-
-               ok(lttng_rate_policy_create_from_payload(
-                                  &view, &policy_from_buffer) > 0 &&
-                                               policy_from_buffer != NULL,
-                               "Deserializing");
-       }
-
-       ok(lttng_rate_policy_is_equal(policy_a, policy_from_buffer),
-                       "serialized and from buffer are equal");
-
-       lttng_rate_policy_destroy(policy_a);
-       lttng_rate_policy_destroy(policy_b);
-       lttng_rate_policy_destroy(policy_c);
-       lttng_payload_reset(&payload);
-}
-
-int main(int argc, const char *argv[])
-{
-       plan_tests(NUM_TESTS);
-       test_rate_policy_every_n();
-       test_rate_policy_once_after_n();
-       return exit_status();
-}
diff --git a/tests/unit/test_rate_policy.cpp b/tests/unit/test_rate_policy.cpp
new file mode 100644 (file)
index 0000000..acfe159
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+ * Unit tests for the rate policy object API.
+ *
+ * Copyright (C) 2019 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <tap/tap.h>
+
+#include <common/payload-view.h>
+#include <common/payload.h>
+#include <lttng/action/rate-policy-internal.h>
+#include <lttng/action/rate-policy.h>
+
+/* For error.h. */
+int lttng_opt_quiet = 1;
+int lttng_opt_verbose;
+int lttng_opt_mi;
+
+#define NUM_TESTS 42
+
+static void test_rate_policy_every_n(void)
+{
+       enum lttng_rate_policy_status status;
+       struct lttng_rate_policy *policy_a = NULL; /* Interval of 100. */
+       struct lttng_rate_policy *policy_b = NULL; /* Interval of 100 */
+       struct lttng_rate_policy *policy_c = NULL; /* Interval of 1 */
+       struct lttng_rate_policy *policy_from_buffer = NULL;
+       uint64_t interval_a_b = 100;
+       uint64_t interval_c = 1;
+       uint64_t interval_query = 0;
+       struct lttng_payload payload;
+
+       lttng_payload_init(&payload);
+
+       policy_a = lttng_rate_policy_every_n_create(interval_a_b);
+       policy_b = lttng_rate_policy_every_n_create(interval_a_b);
+       policy_c = lttng_rate_policy_every_n_create(interval_c);
+       ok(policy_a != NULL,
+                       "Rate policy every n A created: interval: %" PRIu64,
+                       interval_a_b);
+       ok(policy_b != NULL,
+                       "Rate policy every n B created: interval: %" PRIu64,
+                       interval_a_b);
+       ok(policy_c != NULL,
+                       "Rate policy every n C created: interval: %" PRIu64,
+                       interval_c);
+
+       ok(LTTNG_RATE_POLICY_TYPE_EVERY_N ==
+                                       lttng_rate_policy_get_type(policy_a),
+                       "Type is LTTNG_RATE_POLICY_TYPE_EVERY_N");
+
+       /* Getter tests */
+       status = lttng_rate_policy_every_n_get_interval(NULL, NULL);
+       ok(status == LTTNG_RATE_POLICY_STATUS_INVALID,
+                       "Get interval returns INVALID");
+
+       status = lttng_rate_policy_every_n_get_interval(NULL, &interval_query);
+       ok(status == LTTNG_RATE_POLICY_STATUS_INVALID,
+                       "Get interval returns INVALID");
+
+       status = lttng_rate_policy_every_n_get_interval(policy_a, NULL);
+       ok(status == LTTNG_RATE_POLICY_STATUS_INVALID,
+                       "Get interval returns INVALID");
+
+       status = lttng_rate_policy_every_n_get_interval(
+                       policy_a, &interval_query);
+       ok(status == LTTNG_RATE_POLICY_STATUS_OK &&
+                                       interval_query == interval_a_b,
+                       " Getting interval A");
+
+       status = lttng_rate_policy_every_n_get_interval(
+                       policy_b, &interval_query);
+       ok(status == LTTNG_RATE_POLICY_STATUS_OK &&
+                                       interval_query == interval_a_b,
+                       " Getting interval B");
+
+       status = lttng_rate_policy_every_n_get_interval(
+                       policy_c, &interval_query);
+       ok(status == LTTNG_RATE_POLICY_STATUS_OK &&
+                                       interval_query == interval_c,
+                       " Getting interval C");
+
+       /* is_equal tests */
+       /* TODO: this is the behaviour introduced by the
+        * lttng_condition_is_equal back in 2017 do we want to fix this and
+        * return true if both are NULL?
+        */
+       ok(false == lttng_rate_policy_is_equal(NULL, NULL),
+                       "is equal (NULL,NULL)");
+       ok(false == lttng_rate_policy_is_equal(policy_a, NULL),
+                       "is equal (object, NULL)");
+       ok(false == lttng_rate_policy_is_equal(NULL, policy_a),
+                       " is equal (NULL, object)");
+       ok(true == lttng_rate_policy_is_equal(policy_a, policy_a),
+                       "is equal (object A, object A)");
+
+       ok(true == lttng_rate_policy_is_equal(policy_a, policy_b),
+                       "is equal (object A, object B");
+       ok(true == lttng_rate_policy_is_equal(policy_b, policy_a),
+                       "is equal (object B, object A");
+
+       ok(false == lttng_rate_policy_is_equal(policy_a, policy_c),
+                       "is equal (object A, object C)");
+       ok(false == lttng_rate_policy_is_equal(policy_c, policy_a),
+                       "is equal (object C, object A)");
+
+       /* Serialization and create_from buffer. */
+       ok(lttng_rate_policy_serialize(policy_a, &payload) == 0, "Serializing");
+       {
+               struct lttng_payload_view view =
+                               lttng_payload_view_from_payload(
+                                               &payload, 0, -1);
+
+               ok(lttng_rate_policy_create_from_payload(
+                                  &view, &policy_from_buffer) > 0 &&
+                                               policy_from_buffer != NULL,
+                               "Deserializing");
+       }
+
+       ok(lttng_rate_policy_is_equal(policy_a, policy_from_buffer),
+                       "serialized and from buffer are equal");
+
+       lttng_rate_policy_destroy(policy_a);
+       lttng_rate_policy_destroy(policy_b);
+       lttng_rate_policy_destroy(policy_c);
+       lttng_payload_reset(&payload);
+}
+
+static void test_rate_policy_once_after_n(void)
+{
+       enum lttng_rate_policy_status status;
+       struct lttng_rate_policy *policy_a = NULL; /* Threshold of 100. */
+       struct lttng_rate_policy *policy_b = NULL; /* threshold of 100 */
+       struct lttng_rate_policy *policy_c = NULL; /* threshold of 1 */
+       struct lttng_rate_policy *policy_from_buffer = NULL;
+       uint64_t threshold_a_b = 100;
+       uint64_t threshold_c = 1;
+       uint64_t threshold_query = 0;
+       struct lttng_payload payload;
+
+       lttng_payload_init(&payload);
+
+       policy_a = lttng_rate_policy_once_after_n_create(threshold_a_b);
+       policy_b = lttng_rate_policy_once_after_n_create(threshold_a_b);
+       policy_c = lttng_rate_policy_once_after_n_create(threshold_c);
+       ok(policy_a != NULL,
+                       "Rate policy every n A created: threshold: %" PRIu64,
+                       threshold_a_b);
+       ok(policy_b != NULL,
+                       "Rate policy every n B created: threshold: %" PRIu64,
+                       threshold_a_b);
+       ok(policy_c != NULL,
+                       "Rate policy every n C created: threshold: %" PRIu64,
+                       threshold_c);
+
+       ok(LTTNG_RATE_POLICY_TYPE_ONCE_AFTER_N ==
+                                       lttng_rate_policy_get_type(policy_a),
+                       "Type is LTTNG_RATE_POLICY_TYPE_once_after_n");
+
+       /* Getter tests */
+       status = lttng_rate_policy_once_after_n_get_threshold(NULL, NULL);
+       ok(status == LTTNG_RATE_POLICY_STATUS_INVALID,
+                       "Get threshold returns INVALID");
+
+       status = lttng_rate_policy_once_after_n_get_threshold(
+                       NULL, &threshold_query);
+       ok(status == LTTNG_RATE_POLICY_STATUS_INVALID,
+                       "Get threshold returns INVALID");
+
+       status = lttng_rate_policy_once_after_n_get_threshold(policy_a, NULL);
+       ok(status == LTTNG_RATE_POLICY_STATUS_INVALID,
+                       "Get threshold returns INVALID");
+
+       status = lttng_rate_policy_once_after_n_get_threshold(
+                       policy_a, &threshold_query);
+       ok(status == LTTNG_RATE_POLICY_STATUS_OK &&
+                                       threshold_query == threshold_a_b,
+                       " Getting threshold A");
+
+       status = lttng_rate_policy_once_after_n_get_threshold(
+                       policy_b, &threshold_query);
+       ok(status == LTTNG_RATE_POLICY_STATUS_OK &&
+                                       threshold_query == threshold_a_b,
+                       " Getting threshold B");
+
+       status = lttng_rate_policy_once_after_n_get_threshold(
+                       policy_c, &threshold_query);
+       ok(status == LTTNG_RATE_POLICY_STATUS_OK &&
+                                       threshold_query == threshold_c,
+                       " Getting threshold C");
+
+       /* is_equal tests */
+       /* TODO: this is the behaviour introduced by the
+        * lttng_condition_is_equal back in 2017 do we want to fix this and
+        * return true if both are NULL?
+        */
+       ok(false == lttng_rate_policy_is_equal(NULL, NULL),
+                       "is equal (NULL,NULL)");
+       ok(false == lttng_rate_policy_is_equal(policy_a, NULL),
+                       "is equal (object, NULL)");
+       ok(false == lttng_rate_policy_is_equal(NULL, policy_a),
+                       " is equal (NULL, object)");
+       ok(true == lttng_rate_policy_is_equal(policy_a, policy_a),
+                       "is equal (object A, object A)");
+
+       ok(true == lttng_rate_policy_is_equal(policy_a, policy_b),
+                       "is equal (object A, object B");
+       ok(true == lttng_rate_policy_is_equal(policy_b, policy_a),
+                       "is equal (object B, object A");
+
+       ok(false == lttng_rate_policy_is_equal(policy_a, policy_c),
+                       "is equal (object A, object C)");
+       ok(false == lttng_rate_policy_is_equal(policy_c, policy_a),
+                       "is equal (object C, object A)");
+
+       /* Serialization and create_from buffer. */
+       ok(lttng_rate_policy_serialize(policy_a, &payload) == 0, "Serializing");
+       {
+               struct lttng_payload_view view =
+                               lttng_payload_view_from_payload(
+                                               &payload, 0, -1);
+
+               ok(lttng_rate_policy_create_from_payload(
+                                  &view, &policy_from_buffer) > 0 &&
+                                               policy_from_buffer != NULL,
+                               "Deserializing");
+       }
+
+       ok(lttng_rate_policy_is_equal(policy_a, policy_from_buffer),
+                       "serialized and from buffer are equal");
+
+       lttng_rate_policy_destroy(policy_a);
+       lttng_rate_policy_destroy(policy_b);
+       lttng_rate_policy_destroy(policy_c);
+       lttng_payload_reset(&payload);
+}
+
+int main(int argc, const char *argv[])
+{
+       plan_tests(NUM_TESTS);
+       test_rate_policy_every_n();
+       test_rate_policy_once_after_n();
+       return exit_status();
+}
diff --git a/tests/unit/test_string_utils.c b/tests/unit/test_string_utils.c
deleted file mode 100644 (file)
index d2b0d90..0000000
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * Copyright (C) 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-#include <stdlib.h>
-#include <stdbool.h>
-#include <string.h>
-#include <stdarg.h>
-#include <common/string-utils/string-utils.h>
-#include <tap/tap.h>
-
-/* Number of TAP tests in this file */
-#define NUM_TESTS 69
-
-/* For error.h */
-int lttng_opt_quiet = 1;
-int lttng_opt_verbose;
-int lttng_opt_mi;
-
-static void test_one_split(const char *input, char delim, int escape_delim,
-               ...)
-{
-       va_list vl;
-       bool all_ok = true;
-       struct lttng_dynamic_pointer_array strings;
-       int split_ret;
-       size_t i, string_count;
-
-       split_ret = strutils_split(input, delim, escape_delim, &strings);
-       LTTNG_ASSERT(split_ret == 0);
-       va_start(vl, escape_delim);
-
-       string_count = lttng_dynamic_pointer_array_get_count(&strings);
-
-       for (i = 0; i < string_count; i++) {
-               const char *expected_substring = va_arg(vl, const char *);
-               const char *substring =
-                               lttng_dynamic_pointer_array_get_pointer(
-                                               &strings, i);
-
-               diag("  got `%s`, expecting `%s`", substring, expected_substring);
-
-               if (!expected_substring) {
-                       all_ok = false;
-                       break;
-               }
-
-               if (strcmp(substring, expected_substring) != 0) {
-                       all_ok = false;
-                       break;
-               }
-       }
-
-       lttng_dynamic_pointer_array_reset(&strings);
-       va_end(vl);
-       ok(all_ok, "strutils_split() produces the expected substrings: `%s` (delim. `%c`, escape `%d`)",
-                       input, delim, escape_delim);
-}
-
-static void test_split(void)
-{
-       test_one_split("a/b/c/d/e", '/', false, "a", "b", "c", "d", "e", NULL);
-       test_one_split("a/b//d/e", '/', false, "a", "b", "", "d", "e", NULL);
-       test_one_split("/b/c/d/e", '/', false, "", "b", "c", "d", "e", NULL);
-       test_one_split("a/b/c/d/", '/', false, "a", "b", "c", "d", "", NULL);
-       test_one_split("/b/c/d/", '/', false, "", "b", "c", "d", "", NULL);
-       test_one_split("", '/', false, "", NULL);
-       test_one_split("/", '/', false, "", "", NULL);
-       test_one_split("//", '/', false, "", "", "", NULL);
-       test_one_split("hello+world", '+', false, "hello", "world", NULL);
-       test_one_split("hello\\+world", '+', false, "hello\\", "world", NULL);
-       test_one_split("hello\\+world", '+', true, "hello+world", NULL);
-       test_one_split("hello\\++world", '+', true, "hello+", "world", NULL);
-       test_one_split("hello\\\\++world", '+', true, "hello\\\\", "", "world", NULL);
-       test_one_split("hello+world\\", '+', false, "hello", "world\\", NULL);
-       test_one_split("hello+world\\", '+', true, "hello", "world\\", NULL);
-       test_one_split("\\+", '+', false, "\\", "", NULL);
-       test_one_split("\\+", '+', true, "+", NULL);
-}
-
-static void test_one_is_star_at_the_end_only_glob_pattern(const char *pattern, bool expected)
-{
-       ok(strutils_is_star_at_the_end_only_glob_pattern(pattern) == expected,
-               "strutils_is_star_at_the_end_only_glob_pattern() returns the expected result: `%s` -> %d",
-               pattern, expected);
-}
-
-static void test_is_star_at_the_end_only_glob_pattern(void)
-{
-       test_one_is_star_at_the_end_only_glob_pattern("allo*", true);
-       test_one_is_star_at_the_end_only_glob_pattern("allo\\\\*", true);
-       test_one_is_star_at_the_end_only_glob_pattern("allo", false);
-       test_one_is_star_at_the_end_only_glob_pattern("al*lo", false);
-       test_one_is_star_at_the_end_only_glob_pattern("al\\*lo", false);
-       test_one_is_star_at_the_end_only_glob_pattern("*allo", false);
-       test_one_is_star_at_the_end_only_glob_pattern("al*lo*", false);
-       test_one_is_star_at_the_end_only_glob_pattern("allo**", false);
-       test_one_is_star_at_the_end_only_glob_pattern("allo*\\*", false);
-       test_one_is_star_at_the_end_only_glob_pattern("allo\\*", false);
-}
-
-static void test_one_is_star_glob_pattern(const char *pattern, bool expected)
-{
-       ok(strutils_is_star_glob_pattern(pattern) == expected,
-               "strutils_is_star_glob_pattern() returns the expected result: `%s` -> %d",
-               pattern, expected);
-}
-
-static void test_is_star_glob_pattern(void)
-{
-       test_one_is_star_glob_pattern("allo*", true);
-       test_one_is_star_glob_pattern("*allo", true);
-       test_one_is_star_glob_pattern("*allo*", true);
-       test_one_is_star_glob_pattern("*al*lo*", true);
-       test_one_is_star_glob_pattern("al\\**lo", true);
-       test_one_is_star_glob_pattern("al\\*l*o", true);
-       test_one_is_star_glob_pattern("all*o\\", true);
-       test_one_is_star_glob_pattern("*", true);
-       test_one_is_star_glob_pattern("\\\\*", true);
-       test_one_is_star_glob_pattern("allo", false);
-       test_one_is_star_glob_pattern("allo\\*", false);
-       test_one_is_star_glob_pattern("al\\*lo", false);
-       test_one_is_star_glob_pattern("\\*allo", false);
-       test_one_is_star_glob_pattern("\\*", false);
-       test_one_is_star_glob_pattern("allo\\", false);
-}
-
-static void test_one_normalize_star_glob_pattern(const char *pattern,
-               const char *expected)
-{
-       char *rw_pattern = strdup(pattern);
-
-       LTTNG_ASSERT(rw_pattern);
-       strutils_normalize_star_glob_pattern(rw_pattern);
-       ok(strcmp(rw_pattern, expected) == 0,
-               "strutils_normalize_star_glob_pattern() produces the expected result: `%s` -> `%s`",
-               pattern, expected);
-       free(rw_pattern);
-}
-
-static void test_normalize_star_glob_pattern(void)
-{
-       test_one_normalize_star_glob_pattern("salut", "salut");
-       test_one_normalize_star_glob_pattern("sal*ut", "sal*ut");
-       test_one_normalize_star_glob_pattern("sal**ut", "sal*ut");
-       test_one_normalize_star_glob_pattern("sal***ut", "sal*ut");
-       test_one_normalize_star_glob_pattern("*salut", "*salut");
-       test_one_normalize_star_glob_pattern("**salut", "*salut");
-       test_one_normalize_star_glob_pattern("***salut", "*salut");
-       test_one_normalize_star_glob_pattern("salut*", "salut*");
-       test_one_normalize_star_glob_pattern("salut**", "salut*");
-       test_one_normalize_star_glob_pattern("salut***", "salut*");
-       test_one_normalize_star_glob_pattern("sa\\*lut", "sa\\*lut");
-       test_one_normalize_star_glob_pattern("sa\\**lut", "sa\\**lut");
-       test_one_normalize_star_glob_pattern("sa*\\**lut", "sa*\\**lut");
-       test_one_normalize_star_glob_pattern("sa*\\***lut", "sa*\\**lut");
-       test_one_normalize_star_glob_pattern("\\*salu**t", "\\*salu*t");
-       test_one_normalize_star_glob_pattern("\\*salut**", "\\*salut*");
-       test_one_normalize_star_glob_pattern("\\*salut**\\*", "\\*salut*\\*");
-       test_one_normalize_star_glob_pattern("\\*salut", "\\*salut");
-       test_one_normalize_star_glob_pattern("\\***salut", "\\**salut");
-       test_one_normalize_star_glob_pattern("salut\\", "salut\\");
-       test_one_normalize_star_glob_pattern("salut\\**", "salut\\**");
-       test_one_normalize_star_glob_pattern("salut\\\\*", "salut\\\\*");
-       test_one_normalize_star_glob_pattern("salut\\\\***", "salut\\\\*");
-       test_one_normalize_star_glob_pattern("*", "*");
-       test_one_normalize_star_glob_pattern("**", "*");
-       test_one_normalize_star_glob_pattern("***", "*");
-       test_one_normalize_star_glob_pattern("**\\***", "*\\**");
-}
-
-int main(int argc, char **argv)
-{
-       plan_tests(NUM_TESTS);
-       diag("String utils unit tests");
-       test_normalize_star_glob_pattern();
-       test_is_star_glob_pattern();
-       test_is_star_at_the_end_only_glob_pattern();
-       test_split();
-
-       return exit_status();
-}
diff --git a/tests/unit/test_string_utils.cpp b/tests/unit/test_string_utils.cpp
new file mode 100644 (file)
index 0000000..e20f88f
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <stdarg.h>
+#include <common/string-utils/string-utils.h>
+#include <tap/tap.h>
+
+/* Number of TAP tests in this file */
+#define NUM_TESTS 69
+
+/* For error.h */
+int lttng_opt_quiet = 1;
+int lttng_opt_verbose;
+int lttng_opt_mi;
+
+static void test_one_split(const char *input, char delim, int escape_delim,
+               ...)
+{
+       va_list vl;
+       bool all_ok = true;
+       struct lttng_dynamic_pointer_array strings;
+       int split_ret;
+       size_t i, string_count;
+
+       split_ret = strutils_split(input, delim, escape_delim, &strings);
+       LTTNG_ASSERT(split_ret == 0);
+       va_start(vl, escape_delim);
+
+       string_count = lttng_dynamic_pointer_array_get_count(&strings);
+
+       for (i = 0; i < string_count; i++) {
+               const char *expected_substring = va_arg(vl, const char *);
+               const char *substring =
+                       (const char *) lttng_dynamic_pointer_array_get_pointer(
+                               &strings, i);
+
+               diag("  got `%s`, expecting `%s`", substring, expected_substring);
+
+               if (!expected_substring) {
+                       all_ok = false;
+                       break;
+               }
+
+               if (strcmp(substring, expected_substring) != 0) {
+                       all_ok = false;
+                       break;
+               }
+       }
+
+       lttng_dynamic_pointer_array_reset(&strings);
+       va_end(vl);
+       ok(all_ok, "strutils_split() produces the expected substrings: `%s` (delim. `%c`, escape `%d`)",
+                       input, delim, escape_delim);
+}
+
+static void test_split(void)
+{
+       test_one_split("a/b/c/d/e", '/', false, "a", "b", "c", "d", "e", NULL);
+       test_one_split("a/b//d/e", '/', false, "a", "b", "", "d", "e", NULL);
+       test_one_split("/b/c/d/e", '/', false, "", "b", "c", "d", "e", NULL);
+       test_one_split("a/b/c/d/", '/', false, "a", "b", "c", "d", "", NULL);
+       test_one_split("/b/c/d/", '/', false, "", "b", "c", "d", "", NULL);
+       test_one_split("", '/', false, "", NULL);
+       test_one_split("/", '/', false, "", "", NULL);
+       test_one_split("//", '/', false, "", "", "", NULL);
+       test_one_split("hello+world", '+', false, "hello", "world", NULL);
+       test_one_split("hello\\+world", '+', false, "hello\\", "world", NULL);
+       test_one_split("hello\\+world", '+', true, "hello+world", NULL);
+       test_one_split("hello\\++world", '+', true, "hello+", "world", NULL);
+       test_one_split("hello\\\\++world", '+', true, "hello\\\\", "", "world", NULL);
+       test_one_split("hello+world\\", '+', false, "hello", "world\\", NULL);
+       test_one_split("hello+world\\", '+', true, "hello", "world\\", NULL);
+       test_one_split("\\+", '+', false, "\\", "", NULL);
+       test_one_split("\\+", '+', true, "+", NULL);
+}
+
+static void test_one_is_star_at_the_end_only_glob_pattern(const char *pattern, bool expected)
+{
+       ok(strutils_is_star_at_the_end_only_glob_pattern(pattern) == expected,
+               "strutils_is_star_at_the_end_only_glob_pattern() returns the expected result: `%s` -> %d",
+               pattern, expected);
+}
+
+static void test_is_star_at_the_end_only_glob_pattern(void)
+{
+       test_one_is_star_at_the_end_only_glob_pattern("allo*", true);
+       test_one_is_star_at_the_end_only_glob_pattern("allo\\\\*", true);
+       test_one_is_star_at_the_end_only_glob_pattern("allo", false);
+       test_one_is_star_at_the_end_only_glob_pattern("al*lo", false);
+       test_one_is_star_at_the_end_only_glob_pattern("al\\*lo", false);
+       test_one_is_star_at_the_end_only_glob_pattern("*allo", false);
+       test_one_is_star_at_the_end_only_glob_pattern("al*lo*", false);
+       test_one_is_star_at_the_end_only_glob_pattern("allo**", false);
+       test_one_is_star_at_the_end_only_glob_pattern("allo*\\*", false);
+       test_one_is_star_at_the_end_only_glob_pattern("allo\\*", false);
+}
+
+static void test_one_is_star_glob_pattern(const char *pattern, bool expected)
+{
+       ok(strutils_is_star_glob_pattern(pattern) == expected,
+               "strutils_is_star_glob_pattern() returns the expected result: `%s` -> %d",
+               pattern, expected);
+}
+
+static void test_is_star_glob_pattern(void)
+{
+       test_one_is_star_glob_pattern("allo*", true);
+       test_one_is_star_glob_pattern("*allo", true);
+       test_one_is_star_glob_pattern("*allo*", true);
+       test_one_is_star_glob_pattern("*al*lo*", true);
+       test_one_is_star_glob_pattern("al\\**lo", true);
+       test_one_is_star_glob_pattern("al\\*l*o", true);
+       test_one_is_star_glob_pattern("all*o\\", true);
+       test_one_is_star_glob_pattern("*", true);
+       test_one_is_star_glob_pattern("\\\\*", true);
+       test_one_is_star_glob_pattern("allo", false);
+       test_one_is_star_glob_pattern("allo\\*", false);
+       test_one_is_star_glob_pattern("al\\*lo", false);
+       test_one_is_star_glob_pattern("\\*allo", false);
+       test_one_is_star_glob_pattern("\\*", false);
+       test_one_is_star_glob_pattern("allo\\", false);
+}
+
+static void test_one_normalize_star_glob_pattern(const char *pattern,
+               const char *expected)
+{
+       char *rw_pattern = strdup(pattern);
+
+       LTTNG_ASSERT(rw_pattern);
+       strutils_normalize_star_glob_pattern(rw_pattern);
+       ok(strcmp(rw_pattern, expected) == 0,
+               "strutils_normalize_star_glob_pattern() produces the expected result: `%s` -> `%s`",
+               pattern, expected);
+       free(rw_pattern);
+}
+
+static void test_normalize_star_glob_pattern(void)
+{
+       test_one_normalize_star_glob_pattern("salut", "salut");
+       test_one_normalize_star_glob_pattern("sal*ut", "sal*ut");
+       test_one_normalize_star_glob_pattern("sal**ut", "sal*ut");
+       test_one_normalize_star_glob_pattern("sal***ut", "sal*ut");
+       test_one_normalize_star_glob_pattern("*salut", "*salut");
+       test_one_normalize_star_glob_pattern("**salut", "*salut");
+       test_one_normalize_star_glob_pattern("***salut", "*salut");
+       test_one_normalize_star_glob_pattern("salut*", "salut*");
+       test_one_normalize_star_glob_pattern("salut**", "salut*");
+       test_one_normalize_star_glob_pattern("salut***", "salut*");
+       test_one_normalize_star_glob_pattern("sa\\*lut", "sa\\*lut");
+       test_one_normalize_star_glob_pattern("sa\\**lut", "sa\\**lut");
+       test_one_normalize_star_glob_pattern("sa*\\**lut", "sa*\\**lut");
+       test_one_normalize_star_glob_pattern("sa*\\***lut", "sa*\\**lut");
+       test_one_normalize_star_glob_pattern("\\*salu**t", "\\*salu*t");
+       test_one_normalize_star_glob_pattern("\\*salut**", "\\*salut*");
+       test_one_normalize_star_glob_pattern("\\*salut**\\*", "\\*salut*\\*");
+       test_one_normalize_star_glob_pattern("\\*salut", "\\*salut");
+       test_one_normalize_star_glob_pattern("\\***salut", "\\**salut");
+       test_one_normalize_star_glob_pattern("salut\\", "salut\\");
+       test_one_normalize_star_glob_pattern("salut\\**", "salut\\**");
+       test_one_normalize_star_glob_pattern("salut\\\\*", "salut\\\\*");
+       test_one_normalize_star_glob_pattern("salut\\\\***", "salut\\\\*");
+       test_one_normalize_star_glob_pattern("*", "*");
+       test_one_normalize_star_glob_pattern("**", "*");
+       test_one_normalize_star_glob_pattern("***", "*");
+       test_one_normalize_star_glob_pattern("**\\***", "*\\**");
+}
+
+int main(int argc, char **argv)
+{
+       plan_tests(NUM_TESTS);
+       diag("String utils unit tests");
+       test_normalize_star_glob_pattern();
+       test_is_star_glob_pattern();
+       test_is_star_at_the_end_only_glob_pattern();
+       test_split();
+
+       return exit_status();
+}
diff --git a/tests/unit/test_unix_socket.c b/tests/unit/test_unix_socket.c
deleted file mode 100644 (file)
index 8752ba9..0000000
+++ /dev/null
@@ -1,682 +0,0 @@
-/*
- * Copyright (C) 2020 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- */
-
-#include <common/compat/fcntl.h>
-#include <common/sessiond-comm/sessiond-comm.h>
-#include <common/payload.h>
-#include <common/payload-view.h>
-#include <common/unix.h>
-#include <common/utils.h>
-#include <common/defaults.h>
-#include <tap/tap.h>
-#include <stdbool.h>
-#include <common/error.h>
-#include <lttng/constant.h>
-#include <stdio.h>
-#include <pthread.h>
-#include <unistd.h>
-#include <sys/wait.h>
-#include <stdlib.h>
-
-#define HIGH_FD_COUNT LTTCOMM_MAX_SEND_FDS
-#define MESSAGE_COUNT 4
-#define LARGE_PAYLOAD_SIZE 4 * 1024
-#define LARGE_PAYLOAD_RECV_SIZE        100
-
-static const int TEST_COUNT = 37;
-
-/* For error.h */
-int lttng_opt_quiet;
-int lttng_opt_verbose;
-int lttng_opt_mi;
-
-/*
- * Validate that a large number of file descriptors can be received in one shot.
- */
-static void test_high_fd_count(unsigned int fd_count)
-{
-       int sockets[2] = {-1, -1};
-       int ret;
-       unsigned int i;
-       const unsigned int payload_content = 42;
-       struct lttng_payload sent_payload;
-       struct lttng_payload received_payload;
-
-       diag("Send and receive high FD count atomically (%u FDs)", fd_count);
-       lttng_payload_init(&sent_payload);
-       lttng_payload_init(&received_payload);
-
-       ret = lttcomm_create_anon_unix_socketpair(sockets);
-       ok(ret == 0, "Created anonymous unix socket pair");
-       if (ret < 0) {
-               PERROR("Failed to create an anonymous pair of unix sockets");
-               goto error;
-       }
-
-       /* Add dummy content to payload. */
-       ret = lttng_dynamic_buffer_append(&sent_payload.buffer,
-                       &payload_content, sizeof(payload_content));
-       if (ret) {
-               PERROR("Failed to initialize test payload");
-               goto error;
-       }
-
-       for (i = 0; i < fd_count; i++) {
-               struct fd_handle *handle;
-               int fd = fcntl(STDOUT_FILENO, F_DUPFD, 0);
-
-               if (fd < 0) {
-                       PERROR("Failed to create fd while creating test payload");
-                       goto error;
-               }
-
-               handle = fd_handle_create(fd);
-               if (!handle) {
-                       if (close(fd)) {
-                               PERROR("Failed to close fd while preparing test payload");
-                               goto error;
-                       }
-               }
-
-               ret = lttng_payload_push_fd_handle(&sent_payload, handle);
-               fd_handle_put(handle);
-               if (ret) {
-                       PERROR("Failed to add fd handle to test payload");
-                       goto error;
-               }
-       }
-
-       /* Send payload. */
-       {
-               ssize_t sock_ret;
-               struct lttng_payload_view pv = lttng_payload_view_from_payload(
-                               &sent_payload, 0, -1);
-
-               /* Not expected to block considering the size of the payload. */
-               sock_ret = lttcomm_send_unix_sock(
-                               sockets[0], pv.buffer.data, pv.buffer.size);
-               ok(sock_ret == pv.buffer.size, "Sent complete test payload");
-               if (sock_ret != pv.buffer.size) {
-                       ERR("Failed to send test payload bytes: ret = %zd, expected = %zu",
-                                       sock_ret, pv.buffer.size);
-                       goto error;
-               }
-
-               sock_ret = lttcomm_send_payload_view_fds_unix_sock(
-                               sockets[0], &pv);
-               ok(sock_ret == 1, "Sent test payload file descriptors");
-               if (sock_ret != 1) {
-                       if (sock_ret < 0) {
-                               PERROR("Failed to send test payload file descriptors: ret = %zd, expected = %d",
-                                               sock_ret, 1);
-                       } else {
-                               diag("Failed to send test payload file descriptors: ret = %zd, expected = %d",
-                                               sock_ret, 1);
-                       }
-
-                       goto error;
-               }
-       }
-
-       /* Receive payload */
-       {
-               ssize_t sock_ret;
-
-               ret = lttng_dynamic_buffer_set_size(&received_payload.buffer,
-                               sent_payload.buffer.size);
-               if (ret) {
-                       PERROR("Failed to pre-allocate reception buffer");
-                       goto error;
-               }
-
-               sock_ret = lttcomm_recv_unix_sock(sockets[1],
-                               received_payload.buffer.data,
-                               received_payload.buffer.size);
-               ok(sock_ret == received_payload.buffer.size,
-                               "Received payload bytes");
-               if (sock_ret != received_payload.buffer.size) {
-                       ERR("Failed to receive payload bytes: ret = %zd, expected = %zu",
-                                       sock_ret, received_payload.buffer.size);
-                       goto error;
-               }
-
-               sock_ret = lttcomm_recv_payload_fds_unix_sock(
-                               sockets[1], fd_count, &received_payload);
-               ok(sock_ret == (int) (sizeof(int) * fd_count),
-                               "FD reception return value is number of fd * sizeof(int)");
-               if (sock_ret != (int) (sizeof(int) * fd_count)) {
-                       ERR("Failed to receive test payload file descriptors: ret = %zd, expected = %d",
-                                       sock_ret,
-                                       (int) (fd_count * sizeof(int)));
-                       goto error;
-               }
-
-               {
-                       const struct lttng_payload_view pv =
-                                       lttng_payload_view_from_payload(
-                                                       &received_payload, 0,
-                                                       -1);
-                       const int fd_handle_count =
-                                       lttng_payload_view_get_fd_handle_count(
-                                                       &pv);
-
-                       ok(fd_handle_count == fd_count,
-                                       "Received all test payload file descriptors in one invocation");
-               }
-       }
-
-error:
-       for (i = 0; i < 2; i++) {
-               if (sockets[i] < 0) {
-                       continue;
-               }
-
-               if (close(sockets[i])) {
-                       PERROR("Failed to close unix socket");
-               }
-       }
-
-       lttng_payload_reset(&sent_payload);
-       lttng_payload_reset(&received_payload);
-}
-
-/*
- * Validate that if the sender sent multiple messages, each containing 1 fd,
- * the receiver can receive one message at a time (the binary payload and its
- * fd) and is not forced to receive all file descriptors at once.
- */
-static void test_one_fd_per_message(unsigned int message_count)
-{
-       const unsigned int payload_content = 42;
-       int sockets[2] = {-1, -1};
-       int ret;
-       unsigned int i;
-       struct lttng_payload sent_payload;
-       struct lttng_payload received_payload;
-
-       diag("Send and receive small messages with one FD each (%u messages)",
-                       message_count);
-       lttng_payload_init(&sent_payload);
-       lttng_payload_init(&received_payload);
-
-       ret = lttcomm_create_anon_unix_socketpair(sockets);
-       ok(ret == 0, "Created anonymous unix socket pair");
-       if (ret < 0) {
-               PERROR("Failed to create an anonymous pair of unix sockets");
-               goto error;
-       }
-
-       /* Send messages with one fd each. */
-       for (i = 0; i < message_count; i++) {
-               struct fd_handle *handle;
-               int fd;
-
-               /* Add dummy content to payload. */
-               ret = lttng_dynamic_buffer_append(&sent_payload.buffer,
-                               &payload_content, sizeof(payload_content));
-               if (ret) {
-                       PERROR("Failed to initialize test payload");
-                       goto error;
-               }
-
-               fd = fcntl(STDOUT_FILENO, F_DUPFD, 0);
-               if (fd < 0) {
-                       PERROR("Failed to create fd while creating test payload");
-                       goto error;
-               }
-
-               handle = fd_handle_create(fd);
-               if (!handle) {
-                       if (close(fd)) {
-                               PERROR("Failed to close fd while preparing test payload");
-                               goto error;
-                       }
-               }
-
-               ret = lttng_payload_push_fd_handle(&sent_payload, handle);
-               fd_handle_put(handle);
-               if (ret) {
-                       PERROR("Failed to add fd handle to test payload");
-                       goto error;
-               }
-
-               /* Send payload. */
-               {
-                       ssize_t sock_ret;
-                       struct lttng_payload_view pv =
-                                       lttng_payload_view_from_payload(
-                                                       &sent_payload, 0, -1);
-
-                       /* Not expected to block considering the size of the
-                        * payload. */
-                       sock_ret = lttcomm_send_unix_sock(sockets[0],
-                                       pv.buffer.data, pv.buffer.size);
-                       ok(sock_ret == pv.buffer.size,
-                                       "Sent binary payload for message %u",
-                                       i);
-                       if (sock_ret != pv.buffer.size) {
-                               ERR("Failed to send test payload bytes: ret = %zd, expected = %zu",
-                                               sock_ret, pv.buffer.size);
-                               goto error;
-                       }
-
-                       sock_ret = lttcomm_send_payload_view_fds_unix_sock(
-                                       sockets[0], &pv);
-                       ok(sock_ret == 1,
-                                       "Sent file descriptors payload for message %u",
-                                       i);
-                       if (sock_ret != 1) {
-                               if (sock_ret < 0) {
-                                       PERROR("Failed to send test payload file descriptors: ret = %zd, expected = %d",
-                                                       sock_ret, 1);
-                               } else {
-                                       diag("Failed to send test payload file descriptors: ret = %zd, expected = %d",
-                                                       sock_ret, 1);
-                               }
-
-                               goto error;
-                       }
-               }
-
-               lttng_payload_clear(&sent_payload);
-       }
-
-       /* Receive messages one at a time. */
-       for (i = 0; i < message_count; i++) {
-               ssize_t sock_ret;
-
-               ret = lttng_dynamic_buffer_set_size(&received_payload.buffer,
-                               sizeof(payload_content));
-               if (ret) {
-                       PERROR("Failed to pre-allocate reception buffer");
-                       goto error;
-               }
-
-               sock_ret = lttcomm_recv_unix_sock(sockets[1],
-                               received_payload.buffer.data,
-                               received_payload.buffer.size);
-               ok(sock_ret == received_payload.buffer.size,
-                               "Received payload bytes for message %u", i);
-               if (sock_ret != received_payload.buffer.size) {
-                       ERR("Failed to receive payload bytes: ret = %zd, expected = %zu",
-                                       sock_ret, received_payload.buffer.size);
-                       goto error;
-               }
-
-               sock_ret = lttcomm_recv_payload_fds_unix_sock(
-                               sockets[1], 1, &received_payload);
-               ok(sock_ret == (int) sizeof(int), "Received fd for message %u",
-                               i);
-               if (sock_ret != (int) sizeof(int)) {
-                       ERR("Failed to receive test payload file descriptors: ret = %zd, expected = %u",
-                                       sock_ret, (int) sizeof(int));
-                       goto error;
-               }
-
-               {
-                       const struct lttng_payload_view pv =
-                                       lttng_payload_view_from_payload(
-                                                       &received_payload, 0,
-                                                       -1);
-                       const int fd_handle_count =
-                                       lttng_payload_view_get_fd_handle_count(
-                                                       &pv);
-
-                       ok(fd_handle_count == 1,
-                                       "Payload contains 1 fd for message %u",
-                                       i);
-               }
-
-               lttng_payload_clear(&received_payload);
-       }
-
-error:
-       for (i = 0; i < 2; i++) {
-               if (sockets[i] < 0) {
-                       continue;
-               }
-
-               if (close(sockets[i])) {
-                       PERROR("Failed to close unix socket");
-               }
-       }
-
-       lttng_payload_reset(&sent_payload);
-       lttng_payload_reset(&received_payload);
-}
-
-/*
- * Validate that a large message can be received in multiple chunks.
- */
-static void test_receive_in_chunks(
-               unsigned int payload_size, unsigned int max_recv_size)
-{
-       int sockets[2] = {-1, -1};
-       int ret;
-       unsigned int i;
-       struct lttng_payload sent_payload;
-       struct lttng_payload received_payload;
-       struct fd_handle *handle;
-       int fd;
-       ssize_t sock_ret, received = 0;
-
-       diag("Receive a message in multiple chunks");
-       lttng_payload_init(&sent_payload);
-       lttng_payload_init(&received_payload);
-
-       ret = lttcomm_create_anon_unix_socketpair(sockets);
-       ok(ret == 0, "Created anonymous unix socket pair");
-       if (ret < 0) {
-               PERROR("Failed to create an anonymous pair of unix sockets");
-               goto error;
-       }
-
-       /* Add dummy content to payload. */
-       ret = lttng_dynamic_buffer_set_size(&sent_payload.buffer, payload_size);
-       if (ret) {
-               PERROR("Failed to initialize test payload");
-               goto error;
-       }
-
-       fd = fcntl(STDOUT_FILENO, F_DUPFD, 0);
-       if (fd < 0) {
-               PERROR("Failed to create fd while creating test payload");
-               goto error;
-       }
-
-       handle = fd_handle_create(fd);
-       if (!handle) {
-               if (close(fd)) {
-                       PERROR("Failed to close fd while preparing test payload");
-                       goto error;
-               }
-       }
-
-       ret = lttng_payload_push_fd_handle(&sent_payload, handle);
-       fd_handle_put(handle);
-       if (ret) {
-               PERROR("Failed to add fd handle to test payload");
-               goto error;
-       }
-
-       /* Send payload. */
-       {
-               struct lttng_payload_view pv = lttng_payload_view_from_payload(
-                               &sent_payload, 0, -1);
-
-               /* Not expected to block considering the size of the payload. */
-               sock_ret = lttcomm_send_unix_sock(
-                               sockets[0], pv.buffer.data, pv.buffer.size);
-               ok(sock_ret == pv.buffer.size, "Sent complete test payload");
-               if (sock_ret != pv.buffer.size) {
-                       ERR("Failed to send test payload bytes: ret = %zd, expected = %zu",
-                                       sock_ret, pv.buffer.size);
-                       goto error;
-               }
-
-               sock_ret = lttcomm_send_payload_view_fds_unix_sock(
-                               sockets[0], &pv);
-               ok(sock_ret == 1, "Sent test payload file descriptors");
-               if (sock_ret != 1) {
-                       if (sock_ret < 0) {
-                               PERROR("Failed to send test payload file descriptors: ret = %zd, expected = %d",
-                                               sock_ret, 1);
-                       } else {
-                               diag("Failed to send test payload file descriptors: ret = %zd, expected = %d",
-                                               sock_ret, 1);
-                       }
-
-                       goto error;
-               }
-       }
-
-       /* Receive payload */
-       ret = lttng_dynamic_buffer_set_size(
-                       &received_payload.buffer, sent_payload.buffer.size);
-       if (ret) {
-               PERROR("Failed to pre-allocate reception buffer");
-               goto error;
-       }
-
-       do {
-               const ssize_t to_receive_this_pass = min(max_recv_size,
-                               sent_payload.buffer.size - received);
-
-               sock_ret = lttcomm_recv_unix_sock(sockets[1],
-                               received_payload.buffer.data + received,
-                               to_receive_this_pass);
-               if (sock_ret != to_receive_this_pass) {
-                       ERR("Failed to receive payload bytes: ret = %zd, expected = %zu",
-                                       sock_ret, to_receive_this_pass);
-                       break;
-               }
-
-               received += sock_ret;
-       } while (received < sent_payload.buffer.size);
-
-       ok(received == sent_payload.buffer.size,
-                       "Received complete payload in chunks of %u bytes",
-                       max_recv_size);
-       if (received != sent_payload.buffer.size) {
-               goto error;
-       }
-
-       sock_ret = lttcomm_recv_payload_fds_unix_sock(
-                       sockets[1], 1, &received_payload);
-       ok(sock_ret == (int) sizeof(int),
-                       "Received file descriptor after receiving payload in chunks");
-       if (sock_ret != (int) sizeof(int)) {
-               ERR("Failed to receive test payload file descriptors: ret = %zd, expected = %d",
-                               sock_ret, (int) sizeof(int));
-               goto error;
-       }
-
-       {
-               const struct lttng_payload_view pv =
-                               lttng_payload_view_from_payload(
-                                               &received_payload, 0, -1);
-               const int fd_handle_count =
-                               lttng_payload_view_get_fd_handle_count(&pv);
-
-               ok(fd_handle_count == 1,
-                               "Payload contains 1 fd after receiving payload in chunks");
-       }
-
-error:
-       for (i = 0; i < 2; i++) {
-               if (sockets[i] < 0) {
-                       continue;
-               }
-
-               if (close(sockets[i])) {
-                       PERROR("Failed to close unix socket");
-               }
-       }
-
-       lttng_payload_reset(&sent_payload);
-       lttng_payload_reset(&received_payload);
-}
-
-static
-void test_creds_passing(void)
-{
-       pid_t fork_ret = -1;
-       int ret, parent_socket = -1, child_connection_socket = -1;
-       ssize_t sock_ret;
-       char socket_dir_path[] = "/tmp/test.unix.socket.creds.passing.XXXXXX";
-       char socket_path[PATH_MAX] = {};
-       struct expected_creds {
-               uid_t euid;
-               gid_t egid;
-               pid_t pid;
-       } expected_creds;
-
-       diag("Receive peer's effective uid, effective gid, and pid from a unix socket");
-
-       if (!mkdtemp(socket_dir_path)) {
-               PERROR("Failed to generate temporary socket location");
-               goto error;
-       }
-
-       strncat(socket_path, socket_dir_path,
-                       sizeof(socket_path) - strlen(socket_path) - 1);
-       strncat(socket_path, "/test_unix_socket",
-                       sizeof(socket_path) - strlen(socket_path) - 1);
-
-       parent_socket = lttcomm_create_unix_sock(socket_path);
-       ok(parent_socket >= 0, "Created unix socket at path `%s`", socket_path);
-       if (parent_socket < 0) {
-               PERROR("Failed to create unix socket at path `%s`", socket_path);
-               goto error;
-       }
-
-       ret = lttcomm_listen_unix_sock(parent_socket);
-       if (ret < 0) {
-               PERROR("Failed to mark parent socket as a passive socket");
-               goto error;
-       }
-
-       ret = lttcomm_setsockopt_creds_unix_sock(parent_socket);
-       if (ret) {
-               PERROR("Failed to set SO_PASSCRED on parent socket");
-               goto error;
-       }
-
-       fork_ret = fork();
-       if (fork_ret < 0) {
-               PERROR("Failed to fork");
-               goto error;
-       }
-
-       if (fork_ret == 0) {
-               /* Child. */
-               int child_socket;
-
-               expected_creds = (struct expected_creds){
-                       .euid = geteuid(),
-                       .egid = getegid(),
-                       .pid = getpid(),
-               };
-
-               child_socket = lttcomm_connect_unix_sock(socket_path);
-               if (child_socket < 0) {
-                       PERROR("Failed to connect to parent socket");
-                       goto error;
-               }
-
-               ret = lttcomm_setsockopt_creds_unix_sock(child_socket);
-               if (ret) {
-                       PERROR("Failed to set SO_PASSCRED on child socket");
-               }
-
-               sock_ret = lttcomm_send_creds_unix_sock(child_socket, &expected_creds,
-                               sizeof(expected_creds));
-               if (sock_ret < 0) {
-                       PERROR("Failed to send expected credentials");
-               }
-
-               ret = close(child_socket);
-               if (ret) {
-                       PERROR("Failed to close child socket");
-               }
-       } else {
-               /* Parent. */
-               int child_status;
-               pid_t wait_pid_ret;
-               lttng_sock_cred received_creds = {};
-
-               child_connection_socket =
-                               lttcomm_accept_unix_sock(parent_socket);
-               if (child_connection_socket < 0) {
-                       PERROR();
-                       goto error;
-               }
-
-               ret = lttcomm_setsockopt_creds_unix_sock(
-                               child_connection_socket);
-               if (ret) {
-                       PERROR("Failed to set SO_PASSCRED on child connection socket");
-                       goto error;
-               }
-
-               sock_ret = lttcomm_recv_creds_unix_sock(child_connection_socket,
-                               &expected_creds, sizeof(expected_creds),
-                               &received_creds);
-               if (sock_ret < 0) {
-                       PERROR("Failed to receive credentials");
-                       goto error;
-               }
-
-               wait_pid_ret = waitpid(fork_ret, &child_status, 0);
-               if (wait_pid_ret == -1) {
-                       PERROR("Failed to wait for termination of child process");
-                       goto error;
-               }
-               if (!WIFEXITED(child_status) || WEXITSTATUS(child_status)) {
-                       diag("Child process reported an error, test failed");
-                       goto error;
-               }
-
-               ok(expected_creds.euid == received_creds.uid,
-                               "Received the expected effective uid (%d == %d)",
-                               expected_creds.euid, received_creds.uid);
-               ok(expected_creds.egid == received_creds.gid,
-                               "Received the expected effective gid (%d == %d)",
-                               expected_creds.egid, received_creds.gid);
-               ok(expected_creds.pid == received_creds.pid,
-                               "Received the expected pid (%d == %d)",
-                               expected_creds.pid, received_creds.pid);
-       }
-
-error:
-       if (parent_socket >= 0) {
-               ret = close(parent_socket);
-               if (ret) {
-                       PERROR("Failed to close parent socket");
-               }
-       }
-
-       if (fork_ret == 0) {
-               /* Prevent libtap from printing a result for the child. */
-               fclose(stdout);
-               fclose(stderr);
-
-               /* Child exits at the end of this test. */
-               exit(0);
-       } else if (parent_socket >= 0) {
-               if (child_connection_socket >= 0) {
-                       ret = close(child_connection_socket);
-                       if (ret) {
-                               PERROR("Failed to close child connection socket");
-                       }
-               }
-
-               ret = unlink(socket_path);
-               if (ret) {
-                       PERROR("Failed to unlink socket at path `%s`",
-                                       socket_path);
-               }
-
-               ret = rmdir(socket_dir_path);
-               if (ret) {
-                       PERROR("Failed to remove test directory at `%s`",
-                                       socket_dir_path);
-               }
-       }
-}
-
-int main(void)
-{
-       plan_tests(TEST_COUNT);
-
-       test_high_fd_count(HIGH_FD_COUNT);
-       test_one_fd_per_message(MESSAGE_COUNT);
-       test_receive_in_chunks(LARGE_PAYLOAD_SIZE, LARGE_PAYLOAD_RECV_SIZE);
-       test_creds_passing();
-
-       return exit_status();
-}
diff --git a/tests/unit/test_unix_socket.cpp b/tests/unit/test_unix_socket.cpp
new file mode 100644 (file)
index 0000000..2d59ba8
--- /dev/null
@@ -0,0 +1,684 @@
+/*
+ * Copyright (C) 2020 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#include <algorithm>
+#include <common/compat/fcntl.h>
+#include <common/sessiond-comm/sessiond-comm.h>
+#include <common/payload.h>
+#include <common/payload-view.h>
+#include <common/unix.h>
+#include <common/utils.h>
+#include <common/defaults.h>
+#include <tap/tap.h>
+#include <stdbool.h>
+#include <common/error.h>
+#include <lttng/constant.h>
+#include <stdio.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <stdlib.h>
+
+#define HIGH_FD_COUNT LTTCOMM_MAX_SEND_FDS
+#define MESSAGE_COUNT 4
+#define LARGE_PAYLOAD_SIZE 4 * 1024
+#define LARGE_PAYLOAD_RECV_SIZE        100
+
+static const int TEST_COUNT = 37;
+
+/* For error.h */
+int lttng_opt_quiet;
+int lttng_opt_verbose;
+int lttng_opt_mi;
+
+/*
+ * Validate that a large number of file descriptors can be received in one shot.
+ */
+static void test_high_fd_count(unsigned int fd_count)
+{
+       int sockets[2] = {-1, -1};
+       int ret;
+       unsigned int i;
+       const unsigned int payload_content = 42;
+       struct lttng_payload sent_payload;
+       struct lttng_payload received_payload;
+
+       diag("Send and receive high FD count atomically (%u FDs)", fd_count);
+       lttng_payload_init(&sent_payload);
+       lttng_payload_init(&received_payload);
+
+       ret = lttcomm_create_anon_unix_socketpair(sockets);
+       ok(ret == 0, "Created anonymous unix socket pair");
+       if (ret < 0) {
+               PERROR("Failed to create an anonymous pair of unix sockets");
+               goto error;
+       }
+
+       /* Add dummy content to payload. */
+       ret = lttng_dynamic_buffer_append(&sent_payload.buffer,
+                       &payload_content, sizeof(payload_content));
+       if (ret) {
+               PERROR("Failed to initialize test payload");
+               goto error;
+       }
+
+       for (i = 0; i < fd_count; i++) {
+               struct fd_handle *handle;
+               int fd = fcntl(STDOUT_FILENO, F_DUPFD, 0);
+
+               if (fd < 0) {
+                       PERROR("Failed to create fd while creating test payload");
+                       goto error;
+               }
+
+               handle = fd_handle_create(fd);
+               if (!handle) {
+                       if (close(fd)) {
+                               PERROR("Failed to close fd while preparing test payload");
+                               goto error;
+                       }
+               }
+
+               ret = lttng_payload_push_fd_handle(&sent_payload, handle);
+               fd_handle_put(handle);
+               if (ret) {
+                       PERROR("Failed to add fd handle to test payload");
+                       goto error;
+               }
+       }
+
+       /* Send payload. */
+       {
+               ssize_t sock_ret;
+               struct lttng_payload_view pv = lttng_payload_view_from_payload(
+                               &sent_payload, 0, -1);
+
+               /* Not expected to block considering the size of the payload. */
+               sock_ret = lttcomm_send_unix_sock(
+                               sockets[0], pv.buffer.data, pv.buffer.size);
+               ok(sock_ret == pv.buffer.size, "Sent complete test payload");
+               if (sock_ret != pv.buffer.size) {
+                       ERR("Failed to send test payload bytes: ret = %zd, expected = %zu",
+                                       sock_ret, pv.buffer.size);
+                       goto error;
+               }
+
+               sock_ret = lttcomm_send_payload_view_fds_unix_sock(
+                               sockets[0], &pv);
+               ok(sock_ret == 1, "Sent test payload file descriptors");
+               if (sock_ret != 1) {
+                       if (sock_ret < 0) {
+                               PERROR("Failed to send test payload file descriptors: ret = %zd, expected = %d",
+                                               sock_ret, 1);
+                       } else {
+                               diag("Failed to send test payload file descriptors: ret = %zd, expected = %d",
+                                               sock_ret, 1);
+                       }
+
+                       goto error;
+               }
+       }
+
+       /* Receive payload */
+       {
+               ssize_t sock_ret;
+
+               ret = lttng_dynamic_buffer_set_size(&received_payload.buffer,
+                               sent_payload.buffer.size);
+               if (ret) {
+                       PERROR("Failed to pre-allocate reception buffer");
+                       goto error;
+               }
+
+               sock_ret = lttcomm_recv_unix_sock(sockets[1],
+                               received_payload.buffer.data,
+                               received_payload.buffer.size);
+               ok(sock_ret == received_payload.buffer.size,
+                               "Received payload bytes");
+               if (sock_ret != received_payload.buffer.size) {
+                       ERR("Failed to receive payload bytes: ret = %zd, expected = %zu",
+                                       sock_ret, received_payload.buffer.size);
+                       goto error;
+               }
+
+               sock_ret = lttcomm_recv_payload_fds_unix_sock(
+                               sockets[1], fd_count, &received_payload);
+               ok(sock_ret == (int) (sizeof(int) * fd_count),
+                               "FD reception return value is number of fd * sizeof(int)");
+               if (sock_ret != (int) (sizeof(int) * fd_count)) {
+                       ERR("Failed to receive test payload file descriptors: ret = %zd, expected = %d",
+                                       sock_ret,
+                                       (int) (fd_count * sizeof(int)));
+                       goto error;
+               }
+
+               {
+                       const struct lttng_payload_view pv =
+                                       lttng_payload_view_from_payload(
+                                                       &received_payload, 0,
+                                                       -1);
+                       const int fd_handle_count =
+                                       lttng_payload_view_get_fd_handle_count(
+                                                       &pv);
+
+                       ok(fd_handle_count == fd_count,
+                                       "Received all test payload file descriptors in one invocation");
+               }
+       }
+
+error:
+       for (i = 0; i < 2; i++) {
+               if (sockets[i] < 0) {
+                       continue;
+               }
+
+               if (close(sockets[i])) {
+                       PERROR("Failed to close unix socket");
+               }
+       }
+
+       lttng_payload_reset(&sent_payload);
+       lttng_payload_reset(&received_payload);
+}
+
+/*
+ * Validate that if the sender sent multiple messages, each containing 1 fd,
+ * the receiver can receive one message at a time (the binary payload and its
+ * fd) and is not forced to receive all file descriptors at once.
+ */
+static void test_one_fd_per_message(unsigned int message_count)
+{
+       const unsigned int payload_content = 42;
+       int sockets[2] = {-1, -1};
+       int ret;
+       unsigned int i;
+       struct lttng_payload sent_payload;
+       struct lttng_payload received_payload;
+
+       diag("Send and receive small messages with one FD each (%u messages)",
+                       message_count);
+       lttng_payload_init(&sent_payload);
+       lttng_payload_init(&received_payload);
+
+       ret = lttcomm_create_anon_unix_socketpair(sockets);
+       ok(ret == 0, "Created anonymous unix socket pair");
+       if (ret < 0) {
+               PERROR("Failed to create an anonymous pair of unix sockets");
+               goto error;
+       }
+
+       /* Send messages with one fd each. */
+       for (i = 0; i < message_count; i++) {
+               struct fd_handle *handle;
+               int fd;
+
+               /* Add dummy content to payload. */
+               ret = lttng_dynamic_buffer_append(&sent_payload.buffer,
+                               &payload_content, sizeof(payload_content));
+               if (ret) {
+                       PERROR("Failed to initialize test payload");
+                       goto error;
+               }
+
+               fd = fcntl(STDOUT_FILENO, F_DUPFD, 0);
+               if (fd < 0) {
+                       PERROR("Failed to create fd while creating test payload");
+                       goto error;
+               }
+
+               handle = fd_handle_create(fd);
+               if (!handle) {
+                       if (close(fd)) {
+                               PERROR("Failed to close fd while preparing test payload");
+                               goto error;
+                       }
+               }
+
+               ret = lttng_payload_push_fd_handle(&sent_payload, handle);
+               fd_handle_put(handle);
+               if (ret) {
+                       PERROR("Failed to add fd handle to test payload");
+                       goto error;
+               }
+
+               /* Send payload. */
+               {
+                       ssize_t sock_ret;
+                       struct lttng_payload_view pv =
+                                       lttng_payload_view_from_payload(
+                                                       &sent_payload, 0, -1);
+
+                       /* Not expected to block considering the size of the
+                        * payload. */
+                       sock_ret = lttcomm_send_unix_sock(sockets[0],
+                                       pv.buffer.data, pv.buffer.size);
+                       ok(sock_ret == pv.buffer.size,
+                                       "Sent binary payload for message %u",
+                                       i);
+                       if (sock_ret != pv.buffer.size) {
+                               ERR("Failed to send test payload bytes: ret = %zd, expected = %zu",
+                                               sock_ret, pv.buffer.size);
+                               goto error;
+                       }
+
+                       sock_ret = lttcomm_send_payload_view_fds_unix_sock(
+                                       sockets[0], &pv);
+                       ok(sock_ret == 1,
+                                       "Sent file descriptors payload for message %u",
+                                       i);
+                       if (sock_ret != 1) {
+                               if (sock_ret < 0) {
+                                       PERROR("Failed to send test payload file descriptors: ret = %zd, expected = %d",
+                                                       sock_ret, 1);
+                               } else {
+                                       diag("Failed to send test payload file descriptors: ret = %zd, expected = %d",
+                                                       sock_ret, 1);
+                               }
+
+                               goto error;
+                       }
+               }
+
+               lttng_payload_clear(&sent_payload);
+       }
+
+       /* Receive messages one at a time. */
+       for (i = 0; i < message_count; i++) {
+               ssize_t sock_ret;
+
+               ret = lttng_dynamic_buffer_set_size(&received_payload.buffer,
+                               sizeof(payload_content));
+               if (ret) {
+                       PERROR("Failed to pre-allocate reception buffer");
+                       goto error;
+               }
+
+               sock_ret = lttcomm_recv_unix_sock(sockets[1],
+                               received_payload.buffer.data,
+                               received_payload.buffer.size);
+               ok(sock_ret == received_payload.buffer.size,
+                               "Received payload bytes for message %u", i);
+               if (sock_ret != received_payload.buffer.size) {
+                       ERR("Failed to receive payload bytes: ret = %zd, expected = %zu",
+                                       sock_ret, received_payload.buffer.size);
+                       goto error;
+               }
+
+               sock_ret = lttcomm_recv_payload_fds_unix_sock(
+                               sockets[1], 1, &received_payload);
+               ok(sock_ret == (int) sizeof(int), "Received fd for message %u",
+                               i);
+               if (sock_ret != (int) sizeof(int)) {
+                       ERR("Failed to receive test payload file descriptors: ret = %zd, expected = %u",
+                                       sock_ret, (int) sizeof(int));
+                       goto error;
+               }
+
+               {
+                       const struct lttng_payload_view pv =
+                                       lttng_payload_view_from_payload(
+                                                       &received_payload, 0,
+                                                       -1);
+                       const int fd_handle_count =
+                                       lttng_payload_view_get_fd_handle_count(
+                                                       &pv);
+
+                       ok(fd_handle_count == 1,
+                                       "Payload contains 1 fd for message %u",
+                                       i);
+               }
+
+               lttng_payload_clear(&received_payload);
+       }
+
+error:
+       for (i = 0; i < 2; i++) {
+               if (sockets[i] < 0) {
+                       continue;
+               }
+
+               if (close(sockets[i])) {
+                       PERROR("Failed to close unix socket");
+               }
+       }
+
+       lttng_payload_reset(&sent_payload);
+       lttng_payload_reset(&received_payload);
+}
+
+/*
+ * Validate that a large message can be received in multiple chunks.
+ */
+static void test_receive_in_chunks(
+               unsigned int payload_size, unsigned int max_recv_size)
+{
+       int sockets[2] = {-1, -1};
+       int ret;
+       unsigned int i;
+       struct lttng_payload sent_payload;
+       struct lttng_payload received_payload;
+       struct fd_handle *handle;
+       int fd;
+       ssize_t sock_ret, received = 0;
+
+       diag("Receive a message in multiple chunks");
+       lttng_payload_init(&sent_payload);
+       lttng_payload_init(&received_payload);
+
+       ret = lttcomm_create_anon_unix_socketpair(sockets);
+       ok(ret == 0, "Created anonymous unix socket pair");
+       if (ret < 0) {
+               PERROR("Failed to create an anonymous pair of unix sockets");
+               goto error;
+       }
+
+       /* Add dummy content to payload. */
+       ret = lttng_dynamic_buffer_set_size(&sent_payload.buffer, payload_size);
+       if (ret) {
+               PERROR("Failed to initialize test payload");
+               goto error;
+       }
+
+       fd = fcntl(STDOUT_FILENO, F_DUPFD, 0);
+       if (fd < 0) {
+               PERROR("Failed to create fd while creating test payload");
+               goto error;
+       }
+
+       handle = fd_handle_create(fd);
+       if (!handle) {
+               if (close(fd)) {
+                       PERROR("Failed to close fd while preparing test payload");
+                       goto error;
+               }
+       }
+
+       ret = lttng_payload_push_fd_handle(&sent_payload, handle);
+       fd_handle_put(handle);
+       if (ret) {
+               PERROR("Failed to add fd handle to test payload");
+               goto error;
+       }
+
+       /* Send payload. */
+       {
+               struct lttng_payload_view pv = lttng_payload_view_from_payload(
+                               &sent_payload, 0, -1);
+
+               /* Not expected to block considering the size of the payload. */
+               sock_ret = lttcomm_send_unix_sock(
+                               sockets[0], pv.buffer.data, pv.buffer.size);
+               ok(sock_ret == pv.buffer.size, "Sent complete test payload");
+               if (sock_ret != pv.buffer.size) {
+                       ERR("Failed to send test payload bytes: ret = %zd, expected = %zu",
+                                       sock_ret, pv.buffer.size);
+                       goto error;
+               }
+
+               sock_ret = lttcomm_send_payload_view_fds_unix_sock(
+                               sockets[0], &pv);
+               ok(sock_ret == 1, "Sent test payload file descriptors");
+               if (sock_ret != 1) {
+                       if (sock_ret < 0) {
+                               PERROR("Failed to send test payload file descriptors: ret = %zd, expected = %d",
+                                               sock_ret, 1);
+                       } else {
+                               diag("Failed to send test payload file descriptors: ret = %zd, expected = %d",
+                                               sock_ret, 1);
+                       }
+
+                       goto error;
+               }
+       }
+
+       /* Receive payload */
+       ret = lttng_dynamic_buffer_set_size(
+                       &received_payload.buffer, sent_payload.buffer.size);
+       if (ret) {
+               PERROR("Failed to pre-allocate reception buffer");
+               goto error;
+       }
+
+       do {
+               const ssize_t to_receive_this_pass =
+                       std::min<ssize_t>(max_recv_size,
+                               sent_payload.buffer.size - received);
+
+               sock_ret = lttcomm_recv_unix_sock(sockets[1],
+                               received_payload.buffer.data + received,
+                               to_receive_this_pass);
+               if (sock_ret != to_receive_this_pass) {
+                       ERR("Failed to receive payload bytes: ret = %zd, expected = %zu",
+                                       sock_ret, to_receive_this_pass);
+                       break;
+               }
+
+               received += sock_ret;
+       } while (received < sent_payload.buffer.size);
+
+       ok(received == sent_payload.buffer.size,
+                       "Received complete payload in chunks of %u bytes",
+                       max_recv_size);
+       if (received != sent_payload.buffer.size) {
+               goto error;
+       }
+
+       sock_ret = lttcomm_recv_payload_fds_unix_sock(
+                       sockets[1], 1, &received_payload);
+       ok(sock_ret == (int) sizeof(int),
+                       "Received file descriptor after receiving payload in chunks");
+       if (sock_ret != (int) sizeof(int)) {
+               ERR("Failed to receive test payload file descriptors: ret = %zd, expected = %d",
+                               sock_ret, (int) sizeof(int));
+               goto error;
+       }
+
+       {
+               const struct lttng_payload_view pv =
+                               lttng_payload_view_from_payload(
+                                               &received_payload, 0, -1);
+               const int fd_handle_count =
+                               lttng_payload_view_get_fd_handle_count(&pv);
+
+               ok(fd_handle_count == 1,
+                               "Payload contains 1 fd after receiving payload in chunks");
+       }
+
+error:
+       for (i = 0; i < 2; i++) {
+               if (sockets[i] < 0) {
+                       continue;
+               }
+
+               if (close(sockets[i])) {
+                       PERROR("Failed to close unix socket");
+               }
+       }
+
+       lttng_payload_reset(&sent_payload);
+       lttng_payload_reset(&received_payload);
+}
+
+static
+void test_creds_passing(void)
+{
+       pid_t fork_ret = -1;
+       int ret, parent_socket = -1, child_connection_socket = -1;
+       ssize_t sock_ret;
+       char socket_dir_path[] = "/tmp/test.unix.socket.creds.passing.XXXXXX";
+       char socket_path[PATH_MAX] = {};
+       struct expected_creds {
+               uid_t euid;
+               gid_t egid;
+               pid_t pid;
+       } expected_creds;
+
+       diag("Receive peer's effective uid, effective gid, and pid from a unix socket");
+
+       if (!mkdtemp(socket_dir_path)) {
+               PERROR("Failed to generate temporary socket location");
+               goto error;
+       }
+
+       strncat(socket_path, socket_dir_path,
+                       sizeof(socket_path) - strlen(socket_path) - 1);
+       strncat(socket_path, "/test_unix_socket",
+                       sizeof(socket_path) - strlen(socket_path) - 1);
+
+       parent_socket = lttcomm_create_unix_sock(socket_path);
+       ok(parent_socket >= 0, "Created unix socket at path `%s`", socket_path);
+       if (parent_socket < 0) {
+               PERROR("Failed to create unix socket at path `%s`", socket_path);
+               goto error;
+       }
+
+       ret = lttcomm_listen_unix_sock(parent_socket);
+       if (ret < 0) {
+               PERROR("Failed to mark parent socket as a passive socket");
+               goto error;
+       }
+
+       ret = lttcomm_setsockopt_creds_unix_sock(parent_socket);
+       if (ret) {
+               PERROR("Failed to set SO_PASSCRED on parent socket");
+               goto error;
+       }
+
+       fork_ret = fork();
+       if (fork_ret < 0) {
+               PERROR("Failed to fork");
+               goto error;
+       }
+
+       if (fork_ret == 0) {
+               /* Child. */
+               int child_socket;
+
+               expected_creds = (struct expected_creds){
+                       .euid = geteuid(),
+                       .egid = getegid(),
+                       .pid = getpid(),
+               };
+
+               child_socket = lttcomm_connect_unix_sock(socket_path);
+               if (child_socket < 0) {
+                       PERROR("Failed to connect to parent socket");
+                       goto error;
+               }
+
+               ret = lttcomm_setsockopt_creds_unix_sock(child_socket);
+               if (ret) {
+                       PERROR("Failed to set SO_PASSCRED on child socket");
+               }
+
+               sock_ret = lttcomm_send_creds_unix_sock(child_socket, &expected_creds,
+                               sizeof(expected_creds));
+               if (sock_ret < 0) {
+                       PERROR("Failed to send expected credentials");
+               }
+
+               ret = close(child_socket);
+               if (ret) {
+                       PERROR("Failed to close child socket");
+               }
+       } else {
+               /* Parent. */
+               int child_status;
+               pid_t wait_pid_ret;
+               lttng_sock_cred received_creds = {};
+
+               child_connection_socket =
+                               lttcomm_accept_unix_sock(parent_socket);
+               if (child_connection_socket < 0) {
+                       PERROR();
+                       goto error;
+               }
+
+               ret = lttcomm_setsockopt_creds_unix_sock(
+                               child_connection_socket);
+               if (ret) {
+                       PERROR("Failed to set SO_PASSCRED on child connection socket");
+                       goto error;
+               }
+
+               sock_ret = lttcomm_recv_creds_unix_sock(child_connection_socket,
+                               &expected_creds, sizeof(expected_creds),
+                               &received_creds);
+               if (sock_ret < 0) {
+                       PERROR("Failed to receive credentials");
+                       goto error;
+               }
+
+               wait_pid_ret = waitpid(fork_ret, &child_status, 0);
+               if (wait_pid_ret == -1) {
+                       PERROR("Failed to wait for termination of child process");
+                       goto error;
+               }
+               if (!WIFEXITED(child_status) || WEXITSTATUS(child_status)) {
+                       diag("Child process reported an error, test failed");
+                       goto error;
+               }
+
+               ok(expected_creds.euid == received_creds.uid,
+                               "Received the expected effective uid (%d == %d)",
+                               expected_creds.euid, received_creds.uid);
+               ok(expected_creds.egid == received_creds.gid,
+                               "Received the expected effective gid (%d == %d)",
+                               expected_creds.egid, received_creds.gid);
+               ok(expected_creds.pid == received_creds.pid,
+                               "Received the expected pid (%d == %d)",
+                               expected_creds.pid, received_creds.pid);
+       }
+
+error:
+       if (parent_socket >= 0) {
+               ret = close(parent_socket);
+               if (ret) {
+                       PERROR("Failed to close parent socket");
+               }
+       }
+
+       if (fork_ret == 0) {
+               /* Prevent libtap from printing a result for the child. */
+               fclose(stdout);
+               fclose(stderr);
+
+               /* Child exits at the end of this test. */
+               exit(0);
+       } else if (parent_socket >= 0) {
+               if (child_connection_socket >= 0) {
+                       ret = close(child_connection_socket);
+                       if (ret) {
+                               PERROR("Failed to close child connection socket");
+                       }
+               }
+
+               ret = unlink(socket_path);
+               if (ret) {
+                       PERROR("Failed to unlink socket at path `%s`",
+                                       socket_path);
+               }
+
+               ret = rmdir(socket_dir_path);
+               if (ret) {
+                       PERROR("Failed to remove test directory at `%s`",
+                                       socket_dir_path);
+               }
+       }
+}
+
+int main(void)
+{
+       plan_tests(TEST_COUNT);
+
+       test_high_fd_count(HIGH_FD_COUNT);
+       test_one_fd_per_message(MESSAGE_COUNT);
+       test_receive_in_chunks(LARGE_PAYLOAD_SIZE, LARGE_PAYLOAD_RECV_SIZE);
+       test_creds_passing();
+
+       return exit_status();
+}
diff --git a/tests/unit/test_uri.c b/tests/unit/test_uri.c
deleted file mode 100644 (file)
index d2ad04b..0000000
+++ /dev/null
@@ -1,256 +0,0 @@
-/*
- * Copyright (C) 2012 David Goulet <dgoulet@efficios.com>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-#include <string.h>
-
-#include <tap/tap.h>
-
-#include <common/uri.h>
-
-/* For error.h */
-int lttng_opt_quiet = 1;
-int lttng_opt_verbose = 3;
-int lttng_opt_mi;
-
-/* Number of TAP tests in this file */
-#define NUM_TESTS 11
-
-static void test_uri_parsing(void)
-{
-       ssize_t size;
-       const char *s_uri1;
-       struct lttng_uri *uri = NULL;
-
-       s_uri1 = "net://localhost";
-
-       size = uri_parse(s_uri1, &uri);
-
-       ok(size == 2 &&
-          uri[0].dtype == LTTNG_DST_IPV4 &&
-          uri[0].utype == LTTNG_URI_DST &&
-          uri[0].stype == 0 &&
-          uri[0].port == 0 &&
-          strlen(uri[0].subdir) == 0 &&
-          strcmp(uri[0].dst.ipv4, "127.0.0.1") == 0 &&
-          uri[1].dtype == LTTNG_DST_IPV4 &&
-          uri[1].utype == LTTNG_URI_DST &&
-          uri[1].stype == 0 &&
-          uri[1].port == 0 &&
-          strlen(uri[1].subdir) == 0 &&
-          strcmp(uri[1].dst.ipv4, "127.0.0.1") == 0,
-          "URI set to net://localhost");
-
-       if (uri) {
-               uri_free(uri);
-               uri = NULL;
-       }
-
-       s_uri1 = "net://localhost:8989:4242/my/test/path";
-
-       size = uri_parse(s_uri1, &uri);
-
-       ok(size == 2 &&
-          uri[0].dtype == LTTNG_DST_IPV4 &&
-          uri[0].utype == LTTNG_URI_DST &&
-          uri[0].stype == 0 &&
-          uri[0].port == 8989 &&
-          strcmp(uri[0].subdir, "my/test/path") == 0 &&
-          strcmp(uri[0].dst.ipv4, "127.0.0.1") == 0 &&
-          uri[1].dtype == LTTNG_DST_IPV4 &&
-          uri[1].utype == LTTNG_URI_DST &&
-          uri[1].stype == 0 &&
-          uri[1].port == 4242 &&
-          strlen(uri[1].subdir) == 0 &&
-          strcmp(uri[1].dst.ipv4, "127.0.0.1") == 0,
-          "URI set to net://localhost:8989:4242/my/test/path");
-
-       if (uri) {
-               uri_free(uri);
-               uri = NULL;
-       }
-
-       s_uri1 = "net://localhost:8989:4242";
-
-       size = uri_parse(s_uri1, &uri);
-
-       ok(size == 2 &&
-          uri[0].dtype == LTTNG_DST_IPV4 &&
-          uri[0].utype == LTTNG_URI_DST &&
-          uri[0].stype == 0 &&
-          uri[0].port == 8989 &&
-          strlen(uri[0].subdir) == 0 &&
-          strcmp(uri[0].dst.ipv4, "127.0.0.1") == 0 &&
-          uri[1].dtype == LTTNG_DST_IPV4 &&
-          uri[1].utype == LTTNG_URI_DST &&
-          uri[1].stype == 0 &&
-          uri[1].port == 4242 &&
-          strlen(uri[1].subdir) == 0 &&
-          strcmp(uri[1].dst.ipv4, "127.0.0.1") == 0,
-          "URI set to net://localhost:8989:4242");
-
-       if (uri) {
-               uri_free(uri);
-               uri = NULL;
-       }
-
-       s_uri1 = "net6://[::1]:8989";
-
-       size = uri_parse(s_uri1, &uri);
-
-       ok(size == 2 &&
-          uri[0].dtype == LTTNG_DST_IPV6 &&
-          uri[0].utype == LTTNG_URI_DST &&
-          uri[0].stype == 0 &&
-          uri[0].port == 8989 &&
-          strlen(uri[0].subdir) == 0 &&
-          strcmp(uri[0].dst.ipv6, "::1") == 0 &&
-          uri[1].dtype == LTTNG_DST_IPV6 &&
-          uri[1].utype == LTTNG_URI_DST &&
-          uri[1].stype == 0 &&
-          uri[1].port == 0 &&
-          strlen(uri[1].subdir) == 0 &&
-          strcmp(uri[1].dst.ipv6, "::1") == 0,
-          "URI set to net6://[::1]:8989");
-
-       if (uri) {
-               uri_free(uri);
-               uri = NULL;
-       }
-
-       s_uri1 = "tcp://42.42.42.42/my/test/path";
-
-       size = uri_parse(s_uri1, &uri);
-
-       ok(size == 1 &&
-          uri[0].dtype == LTTNG_DST_IPV4 &&
-          uri[0].utype == LTTNG_URI_DST &&
-          uri[0].stype == 0 &&
-          uri[0].port == 0 &&
-          strcmp(uri[0].subdir, "my/test/path") == 0 &&
-          strcmp(uri[0].dst.ipv4, "42.42.42.42") == 0,
-          "URI set to tcp://42.42.42.42/my/test/path");
-
-       if (uri) {
-               uri_free(uri);
-               uri = NULL;
-       }
-
-       s_uri1 = "tcp6://[fe80::f66d:4ff:fe53:d220]/my/test/path";
-
-       size = uri_parse(s_uri1, &uri);
-
-       ok(size == 1 &&
-          uri[0].dtype == LTTNG_DST_IPV6 &&
-          uri[0].utype == LTTNG_URI_DST &&
-          uri[0].stype == 0 &&
-          uri[0].port == 0 &&
-          strcmp(uri[0].subdir, "my/test/path") == 0 &&
-          strcmp(uri[0].dst.ipv6, "fe80::f66d:4ff:fe53:d220") == 0,
-          "URI set to tcp6://[fe80::f66d:4ff:fe53:d220]/my/test/path");
-
-       if (uri) {
-               uri_free(uri);
-               uri = NULL;
-       }
-
-       s_uri1 = "file:///my/test/path";
-
-       size = uri_parse(s_uri1, &uri);
-
-       ok(size == 1 &&
-          uri[0].dtype == LTTNG_DST_PATH &&
-          uri[0].utype == LTTNG_URI_DST &&
-          uri[0].stype == 0 &&
-          uri[0].port == 0 &&
-          strlen(uri[0].subdir) == 0 &&
-          strcmp(uri[0].dst.path, "/my/test/path") == 0,
-          "URI set to file:///my/test/path");
-
-       if (uri) {
-               uri_free(uri);
-               uri = NULL;
-       }
-
-       /* FIXME: Noisy on stdout */
-       s_uri1 = "file/my/test/path";
-       size = uri_parse(s_uri1, &uri);
-       ok(size == -1, "Bad URI set to file/my/test/path");
-       LTTNG_ASSERT(!uri);
-
-       s_uri1 = "net://:8999";
-       size = uri_parse(s_uri1, &uri);
-       ok(size == -1, "Bad URI set to net://:8999");
-       LTTNG_ASSERT(!uri);
-}
-
-static void test_uri_cmp(void)
-{
-       struct lttng_uri *uri1, *uri2;
-       const char *s_uri1 = "net://localhost";
-       const char *s_uri2 = "net://localhost:8989:4242";
-       ssize_t size1, size2;
-       int res;
-
-       size1 = uri_parse(s_uri1, &uri1);
-
-       /* Sanity checks */
-       LTTNG_ASSERT(size1 == 2);
-       LTTNG_ASSERT(uri1[0].dtype == LTTNG_DST_IPV4);
-       LTTNG_ASSERT(uri1[0].utype == LTTNG_URI_DST);
-       LTTNG_ASSERT(uri1[0].stype == 0);
-       LTTNG_ASSERT(uri1[0].port == 0);
-       LTTNG_ASSERT(strlen(uri1[0].subdir) == 0);
-       LTTNG_ASSERT(strcmp(uri1[0].dst.ipv4, "127.0.0.1") == 0);
-       LTTNG_ASSERT(uri1[1].dtype == LTTNG_DST_IPV4);
-       LTTNG_ASSERT(uri1[1].utype == LTTNG_URI_DST);
-       LTTNG_ASSERT(uri1[1].stype == 0);
-       LTTNG_ASSERT(uri1[1].port == 0);
-       LTTNG_ASSERT(strlen(uri1[1].subdir) == 0);
-       LTTNG_ASSERT(strcmp(uri1[1].dst.ipv4, "127.0.0.1") == 0);
-
-       size2 = uri_parse(s_uri2, &uri2);
-
-       LTTNG_ASSERT(size2 == 2);
-       LTTNG_ASSERT(uri2[0].dtype == LTTNG_DST_IPV4);
-       LTTNG_ASSERT(uri2[0].utype == LTTNG_URI_DST);
-       LTTNG_ASSERT(uri2[0].stype == 0);
-       LTTNG_ASSERT(uri2[0].port == 8989);
-       LTTNG_ASSERT(strlen(uri2[0].subdir) == 0);
-       LTTNG_ASSERT(strcmp(uri2[0].dst.ipv4, "127.0.0.1") == 0);
-       LTTNG_ASSERT(uri2[1].dtype == LTTNG_DST_IPV4);
-       LTTNG_ASSERT(uri2[1].utype == LTTNG_URI_DST);
-       LTTNG_ASSERT(uri2[1].stype == 0);
-       LTTNG_ASSERT(uri2[1].port == 4242);
-       LTTNG_ASSERT(strlen(uri2[1].subdir) == 0);
-       LTTNG_ASSERT(strcmp(uri2[1].dst.ipv4, "127.0.0.1") == 0);
-
-       res = uri_compare(uri1, uri1);
-
-       ok(res == 0,
-          "URI compare net://localhost == net://localhost");
-
-       res = uri_compare(uri1, uri2);
-
-       ok(res != 0,
-          "URI compare net://localhost != net://localhost:8989:4242");
-
-       uri_free(uri1);
-       uri_free(uri2);
-}
-
-int main(int argc, char **argv)
-{
-       plan_tests(NUM_TESTS);
-
-       diag("URI unit tests");
-
-       test_uri_parsing();
-
-       test_uri_cmp();
-
-       return exit_status();
-}
diff --git a/tests/unit/test_uri.cpp b/tests/unit/test_uri.cpp
new file mode 100644 (file)
index 0000000..d2ad04b
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2012 David Goulet <dgoulet@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#include <string.h>
+
+#include <tap/tap.h>
+
+#include <common/uri.h>
+
+/* For error.h */
+int lttng_opt_quiet = 1;
+int lttng_opt_verbose = 3;
+int lttng_opt_mi;
+
+/* Number of TAP tests in this file */
+#define NUM_TESTS 11
+
+static void test_uri_parsing(void)
+{
+       ssize_t size;
+       const char *s_uri1;
+       struct lttng_uri *uri = NULL;
+
+       s_uri1 = "net://localhost";
+
+       size = uri_parse(s_uri1, &uri);
+
+       ok(size == 2 &&
+          uri[0].dtype == LTTNG_DST_IPV4 &&
+          uri[0].utype == LTTNG_URI_DST &&
+          uri[0].stype == 0 &&
+          uri[0].port == 0 &&
+          strlen(uri[0].subdir) == 0 &&
+          strcmp(uri[0].dst.ipv4, "127.0.0.1") == 0 &&
+          uri[1].dtype == LTTNG_DST_IPV4 &&
+          uri[1].utype == LTTNG_URI_DST &&
+          uri[1].stype == 0 &&
+          uri[1].port == 0 &&
+          strlen(uri[1].subdir) == 0 &&
+          strcmp(uri[1].dst.ipv4, "127.0.0.1") == 0,
+          "URI set to net://localhost");
+
+       if (uri) {
+               uri_free(uri);
+               uri = NULL;
+       }
+
+       s_uri1 = "net://localhost:8989:4242/my/test/path";
+
+       size = uri_parse(s_uri1, &uri);
+
+       ok(size == 2 &&
+          uri[0].dtype == LTTNG_DST_IPV4 &&
+          uri[0].utype == LTTNG_URI_DST &&
+          uri[0].stype == 0 &&
+          uri[0].port == 8989 &&
+          strcmp(uri[0].subdir, "my/test/path") == 0 &&
+          strcmp(uri[0].dst.ipv4, "127.0.0.1") == 0 &&
+          uri[1].dtype == LTTNG_DST_IPV4 &&
+          uri[1].utype == LTTNG_URI_DST &&
+          uri[1].stype == 0 &&
+          uri[1].port == 4242 &&
+          strlen(uri[1].subdir) == 0 &&
+          strcmp(uri[1].dst.ipv4, "127.0.0.1") == 0,
+          "URI set to net://localhost:8989:4242/my/test/path");
+
+       if (uri) {
+               uri_free(uri);
+               uri = NULL;
+       }
+
+       s_uri1 = "net://localhost:8989:4242";
+
+       size = uri_parse(s_uri1, &uri);
+
+       ok(size == 2 &&
+          uri[0].dtype == LTTNG_DST_IPV4 &&
+          uri[0].utype == LTTNG_URI_DST &&
+          uri[0].stype == 0 &&
+          uri[0].port == 8989 &&
+          strlen(uri[0].subdir) == 0 &&
+          strcmp(uri[0].dst.ipv4, "127.0.0.1") == 0 &&
+          uri[1].dtype == LTTNG_DST_IPV4 &&
+          uri[1].utype == LTTNG_URI_DST &&
+          uri[1].stype == 0 &&
+          uri[1].port == 4242 &&
+          strlen(uri[1].subdir) == 0 &&
+          strcmp(uri[1].dst.ipv4, "127.0.0.1") == 0,
+          "URI set to net://localhost:8989:4242");
+
+       if (uri) {
+               uri_free(uri);
+               uri = NULL;
+       }
+
+       s_uri1 = "net6://[::1]:8989";
+
+       size = uri_parse(s_uri1, &uri);
+
+       ok(size == 2 &&
+          uri[0].dtype == LTTNG_DST_IPV6 &&
+          uri[0].utype == LTTNG_URI_DST &&
+          uri[0].stype == 0 &&
+          uri[0].port == 8989 &&
+          strlen(uri[0].subdir) == 0 &&
+          strcmp(uri[0].dst.ipv6, "::1") == 0 &&
+          uri[1].dtype == LTTNG_DST_IPV6 &&
+          uri[1].utype == LTTNG_URI_DST &&
+          uri[1].stype == 0 &&
+          uri[1].port == 0 &&
+          strlen(uri[1].subdir) == 0 &&
+          strcmp(uri[1].dst.ipv6, "::1") == 0,
+          "URI set to net6://[::1]:8989");
+
+       if (uri) {
+               uri_free(uri);
+               uri = NULL;
+       }
+
+       s_uri1 = "tcp://42.42.42.42/my/test/path";
+
+       size = uri_parse(s_uri1, &uri);
+
+       ok(size == 1 &&
+          uri[0].dtype == LTTNG_DST_IPV4 &&
+          uri[0].utype == LTTNG_URI_DST &&
+          uri[0].stype == 0 &&
+          uri[0].port == 0 &&
+          strcmp(uri[0].subdir, "my/test/path") == 0 &&
+          strcmp(uri[0].dst.ipv4, "42.42.42.42") == 0,
+          "URI set to tcp://42.42.42.42/my/test/path");
+
+       if (uri) {
+               uri_free(uri);
+               uri = NULL;
+       }
+
+       s_uri1 = "tcp6://[fe80::f66d:4ff:fe53:d220]/my/test/path";
+
+       size = uri_parse(s_uri1, &uri);
+
+       ok(size == 1 &&
+          uri[0].dtype == LTTNG_DST_IPV6 &&
+          uri[0].utype == LTTNG_URI_DST &&
+          uri[0].stype == 0 &&
+          uri[0].port == 0 &&
+          strcmp(uri[0].subdir, "my/test/path") == 0 &&
+          strcmp(uri[0].dst.ipv6, "fe80::f66d:4ff:fe53:d220") == 0,
+          "URI set to tcp6://[fe80::f66d:4ff:fe53:d220]/my/test/path");
+
+       if (uri) {
+               uri_free(uri);
+               uri = NULL;
+       }
+
+       s_uri1 = "file:///my/test/path";
+
+       size = uri_parse(s_uri1, &uri);
+
+       ok(size == 1 &&
+          uri[0].dtype == LTTNG_DST_PATH &&
+          uri[0].utype == LTTNG_URI_DST &&
+          uri[0].stype == 0 &&
+          uri[0].port == 0 &&
+          strlen(uri[0].subdir) == 0 &&
+          strcmp(uri[0].dst.path, "/my/test/path") == 0,
+          "URI set to file:///my/test/path");
+
+       if (uri) {
+               uri_free(uri);
+               uri = NULL;
+       }
+
+       /* FIXME: Noisy on stdout */
+       s_uri1 = "file/my/test/path";
+       size = uri_parse(s_uri1, &uri);
+       ok(size == -1, "Bad URI set to file/my/test/path");
+       LTTNG_ASSERT(!uri);
+
+       s_uri1 = "net://:8999";
+       size = uri_parse(s_uri1, &uri);
+       ok(size == -1, "Bad URI set to net://:8999");
+       LTTNG_ASSERT(!uri);
+}
+
+static void test_uri_cmp(void)
+{
+       struct lttng_uri *uri1, *uri2;
+       const char *s_uri1 = "net://localhost";
+       const char *s_uri2 = "net://localhost:8989:4242";
+       ssize_t size1, size2;
+       int res;
+
+       size1 = uri_parse(s_uri1, &uri1);
+
+       /* Sanity checks */
+       LTTNG_ASSERT(size1 == 2);
+       LTTNG_ASSERT(uri1[0].dtype == LTTNG_DST_IPV4);
+       LTTNG_ASSERT(uri1[0].utype == LTTNG_URI_DST);
+       LTTNG_ASSERT(uri1[0].stype == 0);
+       LTTNG_ASSERT(uri1[0].port == 0);
+       LTTNG_ASSERT(strlen(uri1[0].subdir) == 0);
+       LTTNG_ASSERT(strcmp(uri1[0].dst.ipv4, "127.0.0.1") == 0);
+       LTTNG_ASSERT(uri1[1].dtype == LTTNG_DST_IPV4);
+       LTTNG_ASSERT(uri1[1].utype == LTTNG_URI_DST);
+       LTTNG_ASSERT(uri1[1].stype == 0);
+       LTTNG_ASSERT(uri1[1].port == 0);
+       LTTNG_ASSERT(strlen(uri1[1].subdir) == 0);
+       LTTNG_ASSERT(strcmp(uri1[1].dst.ipv4, "127.0.0.1") == 0);
+
+       size2 = uri_parse(s_uri2, &uri2);
+
+       LTTNG_ASSERT(size2 == 2);
+       LTTNG_ASSERT(uri2[0].dtype == LTTNG_DST_IPV4);
+       LTTNG_ASSERT(uri2[0].utype == LTTNG_URI_DST);
+       LTTNG_ASSERT(uri2[0].stype == 0);
+       LTTNG_ASSERT(uri2[0].port == 8989);
+       LTTNG_ASSERT(strlen(uri2[0].subdir) == 0);
+       LTTNG_ASSERT(strcmp(uri2[0].dst.ipv4, "127.0.0.1") == 0);
+       LTTNG_ASSERT(uri2[1].dtype == LTTNG_DST_IPV4);
+       LTTNG_ASSERT(uri2[1].utype == LTTNG_URI_DST);
+       LTTNG_ASSERT(uri2[1].stype == 0);
+       LTTNG_ASSERT(uri2[1].port == 4242);
+       LTTNG_ASSERT(strlen(uri2[1].subdir) == 0);
+       LTTNG_ASSERT(strcmp(uri2[1].dst.ipv4, "127.0.0.1") == 0);
+
+       res = uri_compare(uri1, uri1);
+
+       ok(res == 0,
+          "URI compare net://localhost == net://localhost");
+
+       res = uri_compare(uri1, uri2);
+
+       ok(res != 0,
+          "URI compare net://localhost != net://localhost:8989:4242");
+
+       uri_free(uri1);
+       uri_free(uri2);
+}
+
+int main(int argc, char **argv)
+{
+       plan_tests(NUM_TESTS);
+
+       diag("URI unit tests");
+
+       test_uri_parsing();
+
+       test_uri_cmp();
+
+       return exit_status();
+}
diff --git a/tests/unit/test_utils_compat_poll.c b/tests/unit/test_utils_compat_poll.c
deleted file mode 100644 (file)
index 2581f57..0000000
+++ /dev/null
@@ -1,348 +0,0 @@
-/*
- * test_utils_compat_poll.c
- *
- * Unit tests for the compatibility layer of poll/epoll API.
- *
- * Copyright (C) 2019 Yannick Lamarre <ylamarre@efficios.com>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-#include <inttypes.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-
-#include <tap/tap.h>
-
-#include <common/compat/poll.h>
-#include <common/readwrite.h>
-#include <common/pipe.h>
-#include <common/dynamic-array.h>
-
-/* Verification without trashing test order in the child process */
-#define childok(e, test, ...) do { \
-       if (!(e)) { \
-               diag(test, ## __VA_ARGS__); \
-               _exit(EXIT_FAILURE); \
-       } \
-} while(0)
-
-/* For error.h */
-int lttng_opt_quiet = 1;
-int lttng_opt_verbose;
-int lttng_opt_mi;
-
-/*
- * Non-zero 8-bits arbitrary value below 0x7f to ensure no sign extension
- * occurs. Used to verify that the value is properly propagated through the
- * pipe.
- */
-#define MAGIC_VALUE ((char) 0x5A)
-
-#ifdef HAVE_EPOLL
-#define NUM_TESTS 48
-#else
-#define NUM_TESTS 47
-#endif
-
-#ifdef HAVE_EPOLL
-#if defined(HAVE_EPOLL_CREATE1) && defined(EPOLL_CLOEXEC)
-#define CLOE_VALUE EPOLL_CLOEXEC
-#else
-#define CLOE_VALUE FD_CLOEXEC
-#endif
-
-static
-void test_epoll_compat(void)
-{
-       /*
-        * Type conversion present to disable warning of anonymous enum from
-        * compiler.
-        */
-       ok((int) LTTNG_CLOEXEC == (int) CLOE_VALUE, "epoll's CLOEXEC value");
-}
-#endif
-
-static void test_alloc(void)
-{
-       struct lttng_poll_event poll_events;
-
-       lttng_poll_init(&poll_events);
-
-       /* Null pointer */
-       ok(lttng_poll_create(NULL, 1, 0) != 0, "Create over NULL pointer fails");
-       /* Size 0 */
-       ok(lttng_poll_create(&poll_events, 0, 0) != 0, "Create with size 0 fails");
-       /* without CLOEXEC */
-       ok(lttng_poll_create(&poll_events, 1, 0) == 0, "Create valid poll set succeeds");
-       /*
-        * lttng_poll_event structure untested due to incompatibility across
-        * sublayers. lttng_poll_clean cannot be tested. There is no success
-        * criteria. Verify set's max size cases.
-        */
-       lttng_poll_clean(&poll_events);
-}
-
-/* Tests stuff related to what would be handled with epoll_ctl. */
-static void test_add_del(void)
-{
-       struct lttng_poll_event poll_events;
-
-       lttng_poll_init(&poll_events);
-       ok(lttng_poll_add(NULL, 1, LPOLLIN) != 0, "Adding to NULL set fails");
-       ok(lttng_poll_add(&poll_events, 1, LPOLLIN) != 0, "Adding to uninitialized structure fails");
-       ok(lttng_poll_add(&poll_events, -1, LPOLLIN) != 0, "Adding invalid FD fails");
-
-       ok(lttng_poll_create(&poll_events, 1, 0) == 0, "Create a poll set succeeds");
-       ok(LTTNG_POLL_GETNB(&poll_events) == 0, "Set created empty");
-
-       ok(lttng_poll_add(NULL, 1, LPOLLIN) != 0, "Adding to NULL set fails");
-       ok(LTTNG_POLL_GETNB(&poll_events) == 0, "Set still empty");
-       ok(lttng_poll_add(&poll_events, -1, LPOLLIN) != 0, "Adding invalid FD fails");
-       ok(LTTNG_POLL_GETNB(&poll_events) == 0, "Set still empty");
-
-       ok(lttng_poll_add(&poll_events, 1, LPOLLIN) == 0, "Adding valid FD succeeds");
-       ok(LTTNG_POLL_GETNB(&poll_events) == 1, "Nb of elements incremented");
-
-       ok(lttng_poll_del(NULL, 1) != 0, "Removing from NULL set fails");
-       ok(LTTNG_POLL_GETNB(&poll_events) == 1, "Number of FD in set unchanged");
-
-       ok(lttng_poll_del(&poll_events, -1) != 0, "Removing from negative FD fails");
-       ok(LTTNG_POLL_GETNB(&poll_events) == 1, "Number of FD in set unchanged");
-
-       ok(lttng_poll_del(&poll_events, 2) == 0, "Removing invalid FD still succeeds");
-       ok(LTTNG_POLL_GETNB(&poll_events) == 1, "Number of elements unchanged");
-
-       ok(lttng_poll_del(&poll_events, 1) == 0, "Removing valid FD succeeds");
-       ok(LTTNG_POLL_GETNB(&poll_events) == 0, "Nb of elements decremented");
-
-       ok(lttng_poll_del(&poll_events, 1) != 0, "Removing from empty set fails");
-       ok(LTTNG_POLL_GETNB(&poll_events) == 0, "Nb of elements unchanged");
-
-       lttng_poll_clean(&poll_events);
-}
-
-static void test_mod_wait(void)
-{
-       struct lttng_poll_event poll_events;
-       struct lttng_poll_event cpoll_events;
-       int hupfd[2];
-       int infd[2];
-       pid_t cpid;
-       char rbuf = 0, tbuf = MAGIC_VALUE;
-       int wstatus;
-
-       lttng_poll_init(&poll_events);
-       lttng_poll_init(&cpoll_events);
-
-       ok(pipe(hupfd) != -1, "pipe function succeeds");
-       ok(pipe(infd) != -1, "pipe function succeeds");
-
-       cpid = fork();
-       if (cpid == 0) {
-               childok(lttng_poll_create(&cpoll_events, 1, 0) == 0, "Create valid poll set succeeds");
-               childok(lttng_poll_mod(NULL, infd[0], LPOLLIN) == -1, "lttng_poll_mod with invalid input returns an error");
-               childok(lttng_poll_mod(&cpoll_events, infd[0], LPOLLIN) == -1, "lttng_poll_mod with invalid input returns an error");
-               childok(lttng_poll_add(&cpoll_events, infd[0], LPOLLHUP) == 0, "Add valid FD succeeds");
-               childok(lttng_poll_mod(&cpoll_events, -1, LPOLLIN) == -1, "lttng_poll_mod with invalid input returns an error");
-               childok(lttng_poll_mod(&cpoll_events, hupfd[0], LPOLLIN) == 0, "lttng_poll_mod on unincluded FD goes on");
-               childok(lttng_poll_mod(&cpoll_events, infd[0], LPOLLIN) == 0, "Modify event type succeeds");
-               childok(close(infd[1]) == 0, "Close valid FD succeeds");
-               childok(lttng_poll_wait(&cpoll_events, -1) == 1, "Wait on close times out");
-               childok(lttng_read(infd[0], &rbuf, 1) == 1, "Data is present in the pipe");
-               childok(rbuf == MAGIC_VALUE, "Received data is consistent with transmitted data");
-               childok(lttng_poll_del(&cpoll_events, infd[0]) == 0, "Removing valid FD succeeds");
-               childok(close(infd[0]) == 0, "Close valid FD succeeds");
-               childok(close(hupfd[0]) == 0, "Close valid FD succeeds");
-               childok(close(hupfd[1]) == 0, "Close valid FD succeeds");
-               lttng_poll_clean(&cpoll_events);
-               _exit(EXIT_SUCCESS);
-       } else {
-               ok(close(hupfd[1]) == 0, "Close valid FD succeeds");
-               ok(close(infd[0]) == 0, "Close valid FD succeeds");
-
-               ok(lttng_poll_wait(NULL, -1) == -1, "lttng_poll_wait call with invalid input returns error");
-
-               ok(lttng_poll_create(&poll_events, 1, 0) == 0, "Create valid poll set succeeds");
-               ok(lttng_poll_wait(&poll_events, -1) == -1, "lttng_poll_wait call with invalid input returns error");
-               ok(lttng_poll_add(&poll_events, hupfd[0], LPOLLHUP) == 0, "Add valid FD succeeds");
-               ok(lttng_write(infd[1], &tbuf, 1) == 1, "Write to pipe succeeds");
-               ok(lttng_poll_wait(&poll_events, -1) == 1, "Wakes up on one event");
-               ok(lttng_poll_del(&poll_events, hupfd[0]) == 0, "Removing valid FD succeeds");
-               ok(close(hupfd[0]) == 0, "Close valid FD succeeds");
-               ok(close(infd[1]) == 0, "Close valid FD succeeds");
-               lttng_poll_clean(&poll_events);
-               ok(waitpid(cpid, &wstatus, 0) == cpid, "Wait for child exit");
-               ok(WIFEXITED(wstatus) == 1, "Child process exited");
-               ok(WEXITSTATUS(wstatus) == EXIT_SUCCESS, "Child process exited with EXIT_SUCCESS");
-       }
-}
-
-static void destroy_pipe(void *pipe)
-{
-       lttng_pipe_destroy(pipe);
-}
-
-static int run_active_set_combination(unsigned int fd_count,
-               unsigned int active_fds_mask)
-{
-       int ret = 0;
-       unsigned int i;
-       const unsigned int active_fds_count = __builtin_popcount(active_fds_mask);
-       struct lttng_poll_event poll_events;
-       struct lttng_dynamic_pointer_array pipes;
-       struct lttng_pipe *pipe = NULL;
-
-       lttng_poll_init(&poll_events);
-       lttng_dynamic_pointer_array_init(&pipes, destroy_pipe);
-
-       ret = lttng_poll_create(&poll_events, fd_count, 0);
-       if (ret) {
-               diag("Failed to create poll set for %u file descriptors",
-                               fd_count);
-               goto end;
-       }
-
-       for (i = 0; i < fd_count; i++) {
-               pipe = lttng_pipe_open(0);
-
-               if (!pipe) {
-                       diag("Failed to allocate pipe");
-                       ret = -1;
-                       goto end;
-               }
-
-               ret = lttng_poll_add(&poll_events, lttng_pipe_get_readfd(pipe),
-                               LPOLLIN);
-               if (ret) {
-                       diag("Failed to add file descriptor to poll set");
-                       ret = -1;
-                       goto end;
-               }
-
-               ret = lttng_dynamic_pointer_array_add_pointer(&pipes, pipe);
-               if (ret) {
-                       diag("Failed to add pipe to pipes array");
-                       ret = -1;
-                       goto end;
-               }
-
-               /* Ownership transferred to the pointer array. */
-               pipe = NULL;
-       }
-
-       /* Write one byte for all active fds that should be active. */
-       for (i = 0; i < fd_count; i++) {
-               struct lttng_pipe *borrowed_pipe;
-
-               /* Should this fd be made active? */
-               if (!(active_fds_mask & (1 << i))) {
-                       continue;
-               }
-
-               borrowed_pipe = lttng_dynamic_pointer_array_get_pointer(
-                               &pipes, i);
-
-               ret = lttng_pipe_write(
-                               borrowed_pipe, &(char){'a'}, sizeof(char));
-               if (ret != sizeof(char)) {
-                       diag("Failed to write to pipe");
-                       ret = -1;
-                       goto end;
-               }
-       }
-
-       ret = lttng_poll_wait(&poll_events, 0);
-       if (ret != active_fds_count) {
-               diag("lttng_poll_wait returned %d, expected %u active file descriptors",
-                               ret, active_fds_count);
-               ret = -1;
-               goto end;
-       } else {
-               /* Success! */
-               ret = 0;
-       }
-
-end:
-       lttng_dynamic_pointer_array_reset(&pipes);
-       lttng_poll_clean(&poll_events);
-       lttng_pipe_destroy(pipe);
-       return ret;
-}
-
-static void test_active_set_combinations(unsigned int fd_count)
-{
-       unsigned int i, all_active_mask = 0;
-
-       /* Do you really want to test more than 4,294,967,295 combinations? */
-       LTTNG_ASSERT(fd_count <= 32);
-
-       for (i = 0; i < fd_count; i++) {
-               all_active_mask |= (1 << i);
-       }
-
-       for (i = 0; i <= all_active_mask; i++) {
-               const int ret = run_active_set_combination(fd_count, i);
-
-               if (ret) {
-                       goto fail;
-               }
-       }
-
-       pass("Test all combinations of active file descriptors for %u file descriptors", fd_count);
-       return;
-fail:
-       fail("Test all combinations of active file descriptors for %u file descriptors", fd_count);
-}
-
-static void test_func_def(void)
-{
-#ifdef LTTNG_POLL_GETFD
-#define PASS_GETFD 1
-#else
-#define PASS_GETFD 0
-#endif
-
-#ifdef LTTNG_POLL_GETEV
-#define PASS_GETEV 1
-#else
-#define PASS_GETEV 0
-#endif
-
-#ifdef LTTNG_POLL_GETSZ
-#define PASS_GETSZ 1
-#else
-#define PASS_GETSZ 0
-#endif
-
-#ifdef LTTNG_POLL_GET_PREV_FD
-#define PASS_GET_PREV_FD 1
-#else
-#define PASS_GET_PREV_FD 0
-#endif
-
-       ok(lttng_poll_reset == lttng_poll_reset, "lttng_poll_reset is defined");
-       ok(lttng_poll_init == lttng_poll_init , "lttng_poll_init is defined");
-       ok(PASS_GETFD, "GETFD is defined");
-       ok(PASS_GETEV, "GETEV is defined");
-       ok(PASS_GETSZ, "GETSZ is defined");
-       ok(PASS_GET_PREV_FD, "GET_PREV_FD is defined");
-}
-
-int main(void)
-{
-       plan_tests(NUM_TESTS);
-#ifdef HAVE_EPOLL
-       test_epoll_compat();
-#endif
-       test_func_def();
-       test_alloc();
-       test_add_del();
-       test_mod_wait();
-       test_active_set_combinations(8);
-       return exit_status();
-}
diff --git a/tests/unit/test_utils_compat_poll.cpp b/tests/unit/test_utils_compat_poll.cpp
new file mode 100644 (file)
index 0000000..eb6d94a
--- /dev/null
@@ -0,0 +1,350 @@
+/*
+ * test_utils_compat_poll.c
+ *
+ * Unit tests for the compatibility layer of poll/epoll API.
+ *
+ * Copyright (C) 2019 Yannick Lamarre <ylamarre@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <tap/tap.h>
+
+#include <common/compat/poll.h>
+#include <common/readwrite.h>
+#include <common/pipe.h>
+#include <common/dynamic-array.h>
+
+/* Verification without trashing test order in the child process */
+#define childok(e, test, ...) do { \
+       if (!(e)) { \
+               diag(test, ## __VA_ARGS__); \
+               _exit(EXIT_FAILURE); \
+       } \
+} while(0)
+
+/* For error.h */
+int lttng_opt_quiet = 1;
+int lttng_opt_verbose;
+int lttng_opt_mi;
+
+/*
+ * Non-zero 8-bits arbitrary value below 0x7f to ensure no sign extension
+ * occurs. Used to verify that the value is properly propagated through the
+ * pipe.
+ */
+#define MAGIC_VALUE ((char) 0x5A)
+
+#ifdef HAVE_EPOLL
+#define NUM_TESTS 48
+#else
+#define NUM_TESTS 47
+#endif
+
+#ifdef HAVE_EPOLL
+#if defined(HAVE_EPOLL_CREATE1) && defined(EPOLL_CLOEXEC)
+#define CLOE_VALUE EPOLL_CLOEXEC
+#else
+#define CLOE_VALUE FD_CLOEXEC
+#endif
+
+static
+void test_epoll_compat(void)
+{
+       /*
+        * Type conversion present to disable warning of anonymous enum from
+        * compiler.
+        */
+       ok((int) LTTNG_CLOEXEC == (int) CLOE_VALUE, "epoll's CLOEXEC value");
+}
+#endif
+
+static void test_alloc(void)
+{
+       struct lttng_poll_event poll_events;
+
+       lttng_poll_init(&poll_events);
+
+       /* Null pointer */
+       ok(lttng_poll_create(NULL, 1, 0) != 0, "Create over NULL pointer fails");
+       /* Size 0 */
+       ok(lttng_poll_create(&poll_events, 0, 0) != 0, "Create with size 0 fails");
+       /* without CLOEXEC */
+       ok(lttng_poll_create(&poll_events, 1, 0) == 0, "Create valid poll set succeeds");
+       /*
+        * lttng_poll_event structure untested due to incompatibility across
+        * sublayers. lttng_poll_clean cannot be tested. There is no success
+        * criteria. Verify set's max size cases.
+        */
+       lttng_poll_clean(&poll_events);
+}
+
+/* Tests stuff related to what would be handled with epoll_ctl. */
+static void test_add_del(void)
+{
+       struct lttng_poll_event poll_events;
+
+       lttng_poll_init(&poll_events);
+       ok(lttng_poll_add(NULL, 1, LPOLLIN) != 0, "Adding to NULL set fails");
+       ok(lttng_poll_add(&poll_events, 1, LPOLLIN) != 0, "Adding to uninitialized structure fails");
+       ok(lttng_poll_add(&poll_events, -1, LPOLLIN) != 0, "Adding invalid FD fails");
+
+       ok(lttng_poll_create(&poll_events, 1, 0) == 0, "Create a poll set succeeds");
+       ok(LTTNG_POLL_GETNB(&poll_events) == 0, "Set created empty");
+
+       ok(lttng_poll_add(NULL, 1, LPOLLIN) != 0, "Adding to NULL set fails");
+       ok(LTTNG_POLL_GETNB(&poll_events) == 0, "Set still empty");
+       ok(lttng_poll_add(&poll_events, -1, LPOLLIN) != 0, "Adding invalid FD fails");
+       ok(LTTNG_POLL_GETNB(&poll_events) == 0, "Set still empty");
+
+       ok(lttng_poll_add(&poll_events, 1, LPOLLIN) == 0, "Adding valid FD succeeds");
+       ok(LTTNG_POLL_GETNB(&poll_events) == 1, "Nb of elements incremented");
+
+       ok(lttng_poll_del(NULL, 1) != 0, "Removing from NULL set fails");
+       ok(LTTNG_POLL_GETNB(&poll_events) == 1, "Number of FD in set unchanged");
+
+       ok(lttng_poll_del(&poll_events, -1) != 0, "Removing from negative FD fails");
+       ok(LTTNG_POLL_GETNB(&poll_events) == 1, "Number of FD in set unchanged");
+
+       ok(lttng_poll_del(&poll_events, 2) == 0, "Removing invalid FD still succeeds");
+       ok(LTTNG_POLL_GETNB(&poll_events) == 1, "Number of elements unchanged");
+
+       ok(lttng_poll_del(&poll_events, 1) == 0, "Removing valid FD succeeds");
+       ok(LTTNG_POLL_GETNB(&poll_events) == 0, "Nb of elements decremented");
+
+       ok(lttng_poll_del(&poll_events, 1) != 0, "Removing from empty set fails");
+       ok(LTTNG_POLL_GETNB(&poll_events) == 0, "Nb of elements unchanged");
+
+       lttng_poll_clean(&poll_events);
+}
+
+static void test_mod_wait(void)
+{
+       struct lttng_poll_event poll_events;
+       struct lttng_poll_event cpoll_events;
+       int hupfd[2];
+       int infd[2];
+       pid_t cpid;
+       char rbuf = 0, tbuf = MAGIC_VALUE;
+       int wstatus;
+
+       lttng_poll_init(&poll_events);
+       lttng_poll_init(&cpoll_events);
+
+       ok(pipe(hupfd) != -1, "pipe function succeeds");
+       ok(pipe(infd) != -1, "pipe function succeeds");
+
+       cpid = fork();
+       if (cpid == 0) {
+               childok(lttng_poll_create(&cpoll_events, 1, 0) == 0, "Create valid poll set succeeds");
+               childok(lttng_poll_mod(NULL, infd[0], LPOLLIN) == -1, "lttng_poll_mod with invalid input returns an error");
+               childok(lttng_poll_mod(&cpoll_events, infd[0], LPOLLIN) == -1, "lttng_poll_mod with invalid input returns an error");
+               childok(lttng_poll_add(&cpoll_events, infd[0], LPOLLHUP) == 0, "Add valid FD succeeds");
+               childok(lttng_poll_mod(&cpoll_events, -1, LPOLLIN) == -1, "lttng_poll_mod with invalid input returns an error");
+               childok(lttng_poll_mod(&cpoll_events, hupfd[0], LPOLLIN) == 0, "lttng_poll_mod on unincluded FD goes on");
+               childok(lttng_poll_mod(&cpoll_events, infd[0], LPOLLIN) == 0, "Modify event type succeeds");
+               childok(close(infd[1]) == 0, "Close valid FD succeeds");
+               childok(lttng_poll_wait(&cpoll_events, -1) == 1, "Wait on close times out");
+               childok(lttng_read(infd[0], &rbuf, 1) == 1, "Data is present in the pipe");
+               childok(rbuf == MAGIC_VALUE, "Received data is consistent with transmitted data");
+               childok(lttng_poll_del(&cpoll_events, infd[0]) == 0, "Removing valid FD succeeds");
+               childok(close(infd[0]) == 0, "Close valid FD succeeds");
+               childok(close(hupfd[0]) == 0, "Close valid FD succeeds");
+               childok(close(hupfd[1]) == 0, "Close valid FD succeeds");
+               lttng_poll_clean(&cpoll_events);
+               _exit(EXIT_SUCCESS);
+       } else {
+               ok(close(hupfd[1]) == 0, "Close valid FD succeeds");
+               ok(close(infd[0]) == 0, "Close valid FD succeeds");
+
+               ok(lttng_poll_wait(NULL, -1) == -1, "lttng_poll_wait call with invalid input returns error");
+
+               ok(lttng_poll_create(&poll_events, 1, 0) == 0, "Create valid poll set succeeds");
+               ok(lttng_poll_wait(&poll_events, -1) == -1, "lttng_poll_wait call with invalid input returns error");
+               ok(lttng_poll_add(&poll_events, hupfd[0], LPOLLHUP) == 0, "Add valid FD succeeds");
+               ok(lttng_write(infd[1], &tbuf, 1) == 1, "Write to pipe succeeds");
+               ok(lttng_poll_wait(&poll_events, -1) == 1, "Wakes up on one event");
+               ok(lttng_poll_del(&poll_events, hupfd[0]) == 0, "Removing valid FD succeeds");
+               ok(close(hupfd[0]) == 0, "Close valid FD succeeds");
+               ok(close(infd[1]) == 0, "Close valid FD succeeds");
+               lttng_poll_clean(&poll_events);
+               ok(waitpid(cpid, &wstatus, 0) == cpid, "Wait for child exit");
+               ok(WIFEXITED(wstatus) == 1, "Child process exited");
+               ok(WEXITSTATUS(wstatus) == EXIT_SUCCESS, "Child process exited with EXIT_SUCCESS");
+       }
+}
+
+static void destroy_pipe(void *pipe)
+{
+       lttng_pipe_destroy((lttng_pipe *) pipe);
+}
+
+static int run_active_set_combination(unsigned int fd_count,
+               unsigned int active_fds_mask)
+{
+       int ret = 0;
+       unsigned int i;
+       const unsigned int active_fds_count = __builtin_popcount(active_fds_mask);
+       struct lttng_poll_event poll_events;
+       struct lttng_dynamic_pointer_array pipes;
+       struct lttng_pipe *pipe = NULL;
+
+       lttng_poll_init(&poll_events);
+       lttng_dynamic_pointer_array_init(&pipes, destroy_pipe);
+
+       ret = lttng_poll_create(&poll_events, fd_count, 0);
+       if (ret) {
+               diag("Failed to create poll set for %u file descriptors",
+                               fd_count);
+               goto end;
+       }
+
+       for (i = 0; i < fd_count; i++) {
+               pipe = lttng_pipe_open(0);
+
+               if (!pipe) {
+                       diag("Failed to allocate pipe");
+                       ret = -1;
+                       goto end;
+               }
+
+               ret = lttng_poll_add(&poll_events, lttng_pipe_get_readfd(pipe),
+                               LPOLLIN);
+               if (ret) {
+                       diag("Failed to add file descriptor to poll set");
+                       ret = -1;
+                       goto end;
+               }
+
+               ret = lttng_dynamic_pointer_array_add_pointer(&pipes, pipe);
+               if (ret) {
+                       diag("Failed to add pipe to pipes array");
+                       ret = -1;
+                       goto end;
+               }
+
+               /* Ownership transferred to the pointer array. */
+               pipe = NULL;
+       }
+
+       /* Write one byte for all active fds that should be active. */
+       for (i = 0; i < fd_count; i++) {
+               struct lttng_pipe *borrowed_pipe;
+
+               /* Should this fd be made active? */
+               if (!(active_fds_mask & (1 << i))) {
+                       continue;
+               }
+
+               borrowed_pipe =
+                       (lttng_pipe *) lttng_dynamic_pointer_array_get_pointer(
+                               &pipes, i);
+
+               char c = 'a';
+               ret = lttng_pipe_write(
+                       borrowed_pipe, &c, sizeof(char));
+               if (ret != sizeof(char)) {
+                       diag("Failed to write to pipe");
+                       ret = -1;
+                       goto end;
+               }
+       }
+
+       ret = lttng_poll_wait(&poll_events, 0);
+       if (ret != active_fds_count) {
+               diag("lttng_poll_wait returned %d, expected %u active file descriptors",
+                               ret, active_fds_count);
+               ret = -1;
+               goto end;
+       } else {
+               /* Success! */
+               ret = 0;
+       }
+
+end:
+       lttng_dynamic_pointer_array_reset(&pipes);
+       lttng_poll_clean(&poll_events);
+       lttng_pipe_destroy(pipe);
+       return ret;
+}
+
+static void test_active_set_combinations(unsigned int fd_count)
+{
+       unsigned int i, all_active_mask = 0;
+
+       /* Do you really want to test more than 4,294,967,295 combinations? */
+       LTTNG_ASSERT(fd_count <= 32);
+
+       for (i = 0; i < fd_count; i++) {
+               all_active_mask |= (1 << i);
+       }
+
+       for (i = 0; i <= all_active_mask; i++) {
+               const int ret = run_active_set_combination(fd_count, i);
+
+               if (ret) {
+                       goto fail;
+               }
+       }
+
+       pass("Test all combinations of active file descriptors for %u file descriptors", fd_count);
+       return;
+fail:
+       fail("Test all combinations of active file descriptors for %u file descriptors", fd_count);
+}
+
+static void test_func_def(void)
+{
+#ifdef LTTNG_POLL_GETFD
+#define PASS_GETFD 1
+#else
+#define PASS_GETFD 0
+#endif
+
+#ifdef LTTNG_POLL_GETEV
+#define PASS_GETEV 1
+#else
+#define PASS_GETEV 0
+#endif
+
+#ifdef LTTNG_POLL_GETSZ
+#define PASS_GETSZ 1
+#else
+#define PASS_GETSZ 0
+#endif
+
+#ifdef LTTNG_POLL_GET_PREV_FD
+#define PASS_GET_PREV_FD 1
+#else
+#define PASS_GET_PREV_FD 0
+#endif
+
+       ok(lttng_poll_reset == lttng_poll_reset, "lttng_poll_reset is defined");
+       ok(lttng_poll_init == lttng_poll_init , "lttng_poll_init is defined");
+       ok(PASS_GETFD, "GETFD is defined");
+       ok(PASS_GETEV, "GETEV is defined");
+       ok(PASS_GETSZ, "GETSZ is defined");
+       ok(PASS_GET_PREV_FD, "GET_PREV_FD is defined");
+}
+
+int main(void)
+{
+       plan_tests(NUM_TESTS);
+#ifdef HAVE_EPOLL
+       test_epoll_compat();
+#endif
+       test_func_def();
+       test_alloc();
+       test_add_del();
+       test_mod_wait();
+       test_active_set_combinations(8);
+       return exit_status();
+}
diff --git a/tests/unit/test_utils_compat_pthread.c b/tests/unit/test_utils_compat_pthread.c
deleted file mode 100644 (file)
index eb2b7b6..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2020 Michael Jeanson <mjeanson@efficios.com>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-#include <stdio.h>
-#include <string.h>
-#include "common/compat/pthread.h"
-
-#include <tap/tap.h>
-
-#define TEST_NAME_PROPER_LEN 16
-
-int main(int argc, char **argv)
-{
-       int ret;
-       char name1[TEST_NAME_PROPER_LEN];
-       char name2[TEST_NAME_PROPER_LEN];
-       char too_long_name[] = "thisnameistoolong";
-       char short_name[] = "labatt50";
-       char long_name[] = "procrastinating";
-
-       plan_tests(10);
-
-       /* Get the initial thread name */
-       ret = lttng_pthread_getname_np(name1, TEST_NAME_PROPER_LEN);
-       ok(ret == 0, "Get the thread name: '%s'", name1);
-
-       /* Set a thread name of more than 16 bytes, should fail */
-       ret = lttng_pthread_setname_np(too_long_name);
-       ok(ret == ERANGE, "Set a too long thread name: '%s'", too_long_name);
-
-       /* Get the thread name again, shouldn't have changed */
-       ret = lttng_pthread_getname_np(name2, TEST_NAME_PROPER_LEN);
-       ok(ret == 0, "Get the thread name: '%s'", name2);
-       ok(strcmp(name1, name2) == 0, "Compare the initial thread name: '%s' == '%s'", name1, name2);
-
-       /* Set a thread name of less than 16 bytes */
-       ret = lttng_pthread_setname_np(short_name);
-       ok(ret == 0, "Set a short thread name: '%s'", short_name);
-
-       /* Get the thread name again, should be the one we set */
-       ret = lttng_pthread_getname_np(name1, TEST_NAME_PROPER_LEN);
-       ok(ret == 0, "Get a short thread name: '%s'", name1);
-       ok(strcmp(short_name, name1) == 0, "Compare the short thread name: '%s' == '%s'", short_name, name1);
-
-
-       /* Set a thread name of 16 bytes */
-       ret = lttng_pthread_setname_np(long_name);
-       ok(ret == 0, "Set a long thread name: '%s'", long_name);
-
-       /* Get the thread name again, should be the one we set */
-       ret = lttng_pthread_getname_np(name1, TEST_NAME_PROPER_LEN);
-       ok(ret == 0, "Get a long thread name: '%s'", name1);
-       ok(strncmp(long_name, name1, TEST_NAME_PROPER_LEN - 1) == 0, "Compare the long thread name: '%s' == '%s'", long_name, name1);
-
-       return exit_status();
-}
diff --git a/tests/unit/test_utils_compat_pthread.cpp b/tests/unit/test_utils_compat_pthread.cpp
new file mode 100644 (file)
index 0000000..eb2b7b6
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2020 Michael Jeanson <mjeanson@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "common/compat/pthread.h"
+
+#include <tap/tap.h>
+
+#define TEST_NAME_PROPER_LEN 16
+
+int main(int argc, char **argv)
+{
+       int ret;
+       char name1[TEST_NAME_PROPER_LEN];
+       char name2[TEST_NAME_PROPER_LEN];
+       char too_long_name[] = "thisnameistoolong";
+       char short_name[] = "labatt50";
+       char long_name[] = "procrastinating";
+
+       plan_tests(10);
+
+       /* Get the initial thread name */
+       ret = lttng_pthread_getname_np(name1, TEST_NAME_PROPER_LEN);
+       ok(ret == 0, "Get the thread name: '%s'", name1);
+
+       /* Set a thread name of more than 16 bytes, should fail */
+       ret = lttng_pthread_setname_np(too_long_name);
+       ok(ret == ERANGE, "Set a too long thread name: '%s'", too_long_name);
+
+       /* Get the thread name again, shouldn't have changed */
+       ret = lttng_pthread_getname_np(name2, TEST_NAME_PROPER_LEN);
+       ok(ret == 0, "Get the thread name: '%s'", name2);
+       ok(strcmp(name1, name2) == 0, "Compare the initial thread name: '%s' == '%s'", name1, name2);
+
+       /* Set a thread name of less than 16 bytes */
+       ret = lttng_pthread_setname_np(short_name);
+       ok(ret == 0, "Set a short thread name: '%s'", short_name);
+
+       /* Get the thread name again, should be the one we set */
+       ret = lttng_pthread_getname_np(name1, TEST_NAME_PROPER_LEN);
+       ok(ret == 0, "Get a short thread name: '%s'", name1);
+       ok(strcmp(short_name, name1) == 0, "Compare the short thread name: '%s' == '%s'", short_name, name1);
+
+
+       /* Set a thread name of 16 bytes */
+       ret = lttng_pthread_setname_np(long_name);
+       ok(ret == 0, "Set a long thread name: '%s'", long_name);
+
+       /* Get the thread name again, should be the one we set */
+       ret = lttng_pthread_getname_np(name1, TEST_NAME_PROPER_LEN);
+       ok(ret == 0, "Get a long thread name: '%s'", name1);
+       ok(strncmp(long_name, name1, TEST_NAME_PROPER_LEN - 1) == 0, "Compare the long thread name: '%s' == '%s'", long_name, name1);
+
+       return exit_status();
+}
diff --git a/tests/unit/test_utils_expand_path.c b/tests/unit/test_utils_expand_path.c
deleted file mode 100644 (file)
index a55d7cf..0000000
+++ /dev/null
@@ -1,357 +0,0 @@
-/*
- * Copyright (C) 2013 Raphaël Beamonte <raphael.beamonte@gmail.com>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <limits.h>
-
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include <tap/tap.h>
-
-#include <common/utils.h>
-#include <common/common.h>
-
-/* For error.h */
-int lttng_opt_quiet = 1;
-int lttng_opt_verbose = 3;
-int lttng_opt_mi;
-
-struct valid_test_input {
-       const char *input;
-       const char *relative_part;
-       const char *absolute_part;
-};
-
-struct tree_symlink {
-       const char *orig;
-       const char *dest;
-};
-
-struct symlink_test_input {
-       const char *input;
-       const char *expected_result;
-};
-
-/* Valid test cases */
-static struct valid_test_input valid_tests_inputs[] = {
-       { "/a/b/c/d/e",                 "",             "/a/b/c/d/e"    },
-       { "/a//b//c/d/e",               "",             "/a/b/c/d/e"    },
-       { "./a/b/c/d/e",                ".",            "/a/b/c/d/e"    },
-       { "../a/b/c/d/../e",            "..",           "/a/b/c/e"      },
-       { ".././a/b/c/d/./e",           "..",           "/a/b/c/d/e"    },
-       { "../../a/b/c/d/e",            "../..",        "/a/b/c/d/e"    },
-       { "./a/b/../c/d/../e",          ".",            "/a/c/e"        },
-       { "../a/b/../../c/./d/./e",     "..",           "/c/d/e"        },
-       { "../../a/b/../c/d/../../e",   "../..",        "/a/e"          },
-       { "./a/b/c/d/../../../../e",    ".",            "/e"            },
-       { ".././a/b/c/d/./e",           "..",           "/a/b/c/d/e"    },
-       { "a/",                         ".",            "/a/"           },
-       { "a",                          ".",            "/a"            },
-       { "../../",                     "../..",        "/"             },
-       { "../..",                      "../..",        ""              },
-       { "../",                        "..",           "/"             },
-       { "..",                         "..",           ""              },
-       { "./",                         ".",            "/"             },
-       { ".",                          ".",            ""              },
-       { "/../a/b/c/d/e",              "",             "/a/b/c/d/e"    },
-       { "/a/b/c/d/../../../../../e",  "",             "/e"            },
-       { "/..",                        "",             "/"             },
-       { "/a/..",                      "",             "/"             },
-};
-char **valid_tests_expected_results;
-static const int num_valid_tests =
-               sizeof(valid_tests_inputs) / sizeof(valid_tests_inputs[0]);
-
-/* Symlinks test cases */
-char tree_origin[] = "/tmp/test_utils_expand_path.XXXXXX";
-
-static const char * const tree_dirs[] = {
-       "a",
-       "a/b",
-       "a/b/c",
-       "a/e",
-};
-static const int num_tree_dirs =
-               sizeof(tree_dirs) / sizeof(tree_dirs[0]);
-
-static struct tree_symlink tree_symlinks[] = {
-       { "a/d",                        "b/c/"          },
-       { "a/g",                        "d/"            },
-       { "a/b/f",                      "../e/"         },
-       { "a/b/h",                      "../g/"         },
-       { "a/b/k",                      "c/g/"          },
-       { "a/b/c/g",                    "../../../"     },
-};
-static const int num_tree_symlinks =
-               sizeof(tree_symlinks) / sizeof(tree_symlinks[0]);
-
-static struct symlink_test_input symlink_tests_inputs[] = {
-       { "a/g/../l/.",                 "a/b/l"         },
-       { "a/g/../l/./",                "a/b/l/"        },
-       { "a/g/../l/..",                "a/b"           },
-       { "a/g/../l/../",               "a/b/"          },
-       { "a/b/h/g/",                   ""              },
-};
-static const int num_symlink_tests =
-               sizeof(symlink_tests_inputs) / sizeof(symlink_tests_inputs[0]);
-
-/* Invalid test cases */
-static char *invalid_tests_inputs[] = {
-       NULL,
-};
-static const int num_invalid_tests =
-               sizeof(invalid_tests_inputs) / sizeof(invalid_tests_inputs[0]);
-
-#define PRINT_ERR(fmt, args...)                                                \
-       fprintf(stderr, "test_utils_expand_path: error: " fmt "\n", ## args)
-
-static int prepare_valid_results(void)
-{
-       int i;
-       char *relative, *cur_path = NULL, *prev_path = NULL,
-                       *pprev_path = NULL, *empty = NULL;
-       int ret = 0;
-
-       /* Prepare the relative paths */
-       cur_path = realpath(".", NULL);
-       prev_path = realpath("..", NULL);
-       pprev_path = realpath("../..", NULL);
-       empty = strdup("");
-       if (!cur_path || !prev_path || !pprev_path || !empty) {
-               PRINT_ERR("strdup out of memory");
-               ret = -1;
-               goto end;
-       }
-
-       /* allocate memory for the expected results */
-       valid_tests_expected_results = zmalloc(sizeof(char *) * num_valid_tests);
-       if (!valid_tests_expected_results) {
-               PRINT_ERR("out of memory");
-               ret = -1;
-               goto end;
-       }
-       for (i = 0; i < num_valid_tests; i++) {
-               valid_tests_expected_results[i] = malloc(PATH_MAX);
-               if (valid_tests_expected_results[i] == NULL) {
-                       PRINT_ERR("malloc expected results");
-                       ret = -1;
-                       goto end;
-               }
-
-               if (strcmp(valid_tests_inputs[i].relative_part, ".") == 0) {
-                       relative = cur_path;
-               } else if (strcmp(valid_tests_inputs[i].relative_part, "..") == 0) {
-                       relative = prev_path;
-               } else if (strcmp(valid_tests_inputs[i].relative_part, "../..") == 0) {
-                       relative = pprev_path;
-               } else {
-                       relative = empty;
-               }
-
-               snprintf(valid_tests_expected_results[i], PATH_MAX,
-                               "%s%s", relative, valid_tests_inputs[i].absolute_part);
-       }
-
-end:
-       free(cur_path);
-       free(prev_path);
-       free(pprev_path);
-       free(empty);
-
-       return ret;
-}
-
-static int free_valid_results(void)
-{
-       int i;
-
-       for (i = 0; i < num_valid_tests; i++) {
-               free(valid_tests_expected_results[i]);
-       }
-
-       free(valid_tests_expected_results);
-
-       return 0;
-}
-
-static int prepare_symlink_tree(void)
-{
-       int i;
-       char tmppath[PATH_MAX] = {};
-
-       /* Create the temporary directory */
-       if (mkdtemp(tree_origin) == NULL) {
-               PRINT_ERR("failed to mkdtemp");
-               goto error;
-       }
-
-       /* Create the directories of the test tree */
-       for (i = 0; i < num_tree_dirs; i++) {
-               snprintf(tmppath, sizeof(tmppath), "%s/%s", tree_origin,
-                               tree_dirs[i]);
-
-               if (mkdir(tmppath, 0755) != 0) {
-                       PRINT_ERR("mkdir failed with path \"%s\"", tmppath);
-                       goto error;
-               }
-       }
-
-       /* Create the symlinks of the test tree */
-       for (i = 0; i < num_tree_symlinks; i++) {
-               snprintf(tmppath, sizeof(tmppath), "%s/%s",
-                               tree_origin, tree_symlinks[i].orig);
-
-               if (symlink(tree_symlinks[i].dest, tmppath) != 0) {
-                       PRINT_ERR("failed to symlink \"%s\" to \"%s\"", tmppath,
-                                       tree_symlinks[i].dest);
-                       goto error;
-               }
-       }
-
-       return 0;
-
-error:
-       return 1;
-}
-
-static int free_symlink_tree(void)
-{
-       int i;
-       char tmppath[PATH_MAX];
-
-       /* Remove the symlinks from the test tree */
-       for (i =  num_tree_symlinks - 1; i > -1; i--) {
-               snprintf(tmppath, PATH_MAX, "%s/%s",
-                               tree_origin, tree_symlinks[i].orig);
-
-               if (unlink(tmppath) != 0) {
-                       PRINT_ERR("failed to unlink \"%s\"", tmppath);
-                       goto error;
-               }
-       }
-
-       /* Remove the directories from the test tree */
-       for (i = num_tree_dirs - 1; i > -1; i--) {
-               snprintf(tmppath, PATH_MAX, "%s/%s", tree_origin, tree_dirs[i]);
-
-               if (rmdir(tmppath) != 0) {
-                       PRINT_ERR("failed to rmdir \"%s\"", tmppath);
-                       goto error;
-               }
-       }
-
-       /* Remove the temporary directory */
-       if (rmdir(tree_origin) != 0) {
-               PRINT_ERR("failed to rmdir \"%s\"", tree_origin);
-               goto error;
-       }
-
-       return 0;
-
-error:
-       return 1;
-}
-
-static void test_utils_expand_path(void)
-{
-       char *result;
-       char name[100], tmppath[PATH_MAX], real_tree_origin[PATH_MAX];
-       int i, treelen;
-
-       /* Test valid cases */
-       for (i = 0; i < num_valid_tests; i++) {
-               sprintf(name, "valid test case: %s", valid_tests_inputs[i].input);
-
-               result = utils_expand_path(valid_tests_inputs[i].input);
-               ok(result != NULL &&
-                               strcmp(result, valid_tests_expected_results[i]) == 0, name);
-
-               free(result);
-       }
-
-       /*
-        * Get the realpath for the tree_origin since it can itself be a
-        * symlink.
-        */
-       result = realpath(tree_origin, real_tree_origin);
-       if (!result) {
-               fail("realpath failed.");
-               return;
-       }
-
-       /* Test symlink tree cases */
-       treelen = strlen(real_tree_origin) + 1;
-       for (i = 0; i < num_symlink_tests; i++) {
-               int ret;
-
-               sprintf(name, "symlink tree test case: [tmppath/]%s",
-                               symlink_tests_inputs[i].input);
-
-               ret = snprintf(tmppath, PATH_MAX, "%s/%s",
-                               real_tree_origin,
-                               symlink_tests_inputs[i].input);
-               if (ret == -1 || ret >= PATH_MAX) {
-                       PRINT_ERR("truncation occurred while concatenating paths \"%s\" and \"%s\"",
-                                       real_tree_origin,
-                                       symlink_tests_inputs[i].input);
-                       fail(name);
-                       continue;
-               }
-               result = utils_expand_path(tmppath);
-               ok(result != NULL && strcmp(result + treelen,
-                                       symlink_tests_inputs[i].expected_result) == 0, name);
-
-               free(result);
-       }
-
-       /* Test invalid cases */
-       for (i = 0; i < num_invalid_tests; i++) {
-               const char *test_input = invalid_tests_inputs[i];
-
-               sprintf(name, "invalid test case: %s", test_input ?
-                               test_input : "NULL");
-
-               result = utils_expand_path(test_input);
-               if (result != NULL) {
-                       free(result);
-               }
-               ok(result == NULL, name);
-       }
-}
-
-int main(int argc, char **argv)
-{
-       if (prepare_symlink_tree() != 0) {
-               goto error_mkdir;
-       }
-
-       if (prepare_valid_results() != 0) {
-               goto error_malloc;
-       }
-
-       plan_tests(num_valid_tests + num_invalid_tests + num_symlink_tests);
-
-       diag("utils_expand_path tests");
-
-       test_utils_expand_path();
-
-       free_valid_results();
-       free_symlink_tree();
-
-       return exit_status();
-
-error_malloc:
-       free_valid_results();
-
-error_mkdir:
-       free_symlink_tree();
-
-       return 1;
-}
diff --git a/tests/unit/test_utils_expand_path.cpp b/tests/unit/test_utils_expand_path.cpp
new file mode 100644 (file)
index 0000000..428acad
--- /dev/null
@@ -0,0 +1,357 @@
+/*
+ * Copyright (C) 2013 Raphaël Beamonte <raphael.beamonte@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <tap/tap.h>
+
+#include <common/utils.h>
+#include <common/common.h>
+
+/* For error.h */
+int lttng_opt_quiet = 1;
+int lttng_opt_verbose = 3;
+int lttng_opt_mi;
+
+struct valid_test_input {
+       const char *input;
+       const char *relative_part;
+       const char *absolute_part;
+};
+
+struct tree_symlink {
+       const char *orig;
+       const char *dest;
+};
+
+struct symlink_test_input {
+       const char *input;
+       const char *expected_result;
+};
+
+/* Valid test cases */
+static struct valid_test_input valid_tests_inputs[] = {
+       { "/a/b/c/d/e",                 "",             "/a/b/c/d/e"    },
+       { "/a//b//c/d/e",               "",             "/a/b/c/d/e"    },
+       { "./a/b/c/d/e",                ".",            "/a/b/c/d/e"    },
+       { "../a/b/c/d/../e",            "..",           "/a/b/c/e"      },
+       { ".././a/b/c/d/./e",           "..",           "/a/b/c/d/e"    },
+       { "../../a/b/c/d/e",            "../..",        "/a/b/c/d/e"    },
+       { "./a/b/../c/d/../e",          ".",            "/a/c/e"        },
+       { "../a/b/../../c/./d/./e",     "..",           "/c/d/e"        },
+       { "../../a/b/../c/d/../../e",   "../..",        "/a/e"          },
+       { "./a/b/c/d/../../../../e",    ".",            "/e"            },
+       { ".././a/b/c/d/./e",           "..",           "/a/b/c/d/e"    },
+       { "a/",                         ".",            "/a/"           },
+       { "a",                          ".",            "/a"            },
+       { "../../",                     "../..",        "/"             },
+       { "../..",                      "../..",        ""              },
+       { "../",                        "..",           "/"             },
+       { "..",                         "..",           ""              },
+       { "./",                         ".",            "/"             },
+       { ".",                          ".",            ""              },
+       { "/../a/b/c/d/e",              "",             "/a/b/c/d/e"    },
+       { "/a/b/c/d/../../../../../e",  "",             "/e"            },
+       { "/..",                        "",             "/"             },
+       { "/a/..",                      "",             "/"             },
+};
+char **valid_tests_expected_results;
+static const int num_valid_tests =
+               sizeof(valid_tests_inputs) / sizeof(valid_tests_inputs[0]);
+
+/* Symlinks test cases */
+char tree_origin[] = "/tmp/test_utils_expand_path.XXXXXX";
+
+static const char * const tree_dirs[] = {
+       "a",
+       "a/b",
+       "a/b/c",
+       "a/e",
+};
+static const int num_tree_dirs =
+               sizeof(tree_dirs) / sizeof(tree_dirs[0]);
+
+static struct tree_symlink tree_symlinks[] = {
+       { "a/d",                        "b/c/"          },
+       { "a/g",                        "d/"            },
+       { "a/b/f",                      "../e/"         },
+       { "a/b/h",                      "../g/"         },
+       { "a/b/k",                      "c/g/"          },
+       { "a/b/c/g",                    "../../../"     },
+};
+static const int num_tree_symlinks =
+               sizeof(tree_symlinks) / sizeof(tree_symlinks[0]);
+
+static struct symlink_test_input symlink_tests_inputs[] = {
+       { "a/g/../l/.",                 "a/b/l"         },
+       { "a/g/../l/./",                "a/b/l/"        },
+       { "a/g/../l/..",                "a/b"           },
+       { "a/g/../l/../",               "a/b/"          },
+       { "a/b/h/g/",                   ""              },
+};
+static const int num_symlink_tests =
+               sizeof(symlink_tests_inputs) / sizeof(symlink_tests_inputs[0]);
+
+/* Invalid test cases */
+static char *invalid_tests_inputs[] = {
+       NULL,
+};
+static const int num_invalid_tests =
+               sizeof(invalid_tests_inputs) / sizeof(invalid_tests_inputs[0]);
+
+#define PRINT_ERR(fmt, args...)                                                \
+       fprintf(stderr, "test_utils_expand_path: error: " fmt "\n", ## args)
+
+static int prepare_valid_results(void)
+{
+       int i;
+       char *relative, *cur_path = NULL, *prev_path = NULL,
+                       *pprev_path = NULL, *empty = NULL;
+       int ret = 0;
+
+       /* Prepare the relative paths */
+       cur_path = realpath(".", NULL);
+       prev_path = realpath("..", NULL);
+       pprev_path = realpath("../..", NULL);
+       empty = strdup("");
+       if (!cur_path || !prev_path || !pprev_path || !empty) {
+               PRINT_ERR("strdup out of memory");
+               ret = -1;
+               goto end;
+       }
+
+       /* allocate memory for the expected results */
+       valid_tests_expected_results = (char **) zmalloc(sizeof(char *) * num_valid_tests);
+       if (!valid_tests_expected_results) {
+               PRINT_ERR("out of memory");
+               ret = -1;
+               goto end;
+       }
+       for (i = 0; i < num_valid_tests; i++) {
+               valid_tests_expected_results[i] = (char *) malloc(PATH_MAX);
+               if (valid_tests_expected_results[i] == NULL) {
+                       PRINT_ERR("malloc expected results");
+                       ret = -1;
+                       goto end;
+               }
+
+               if (strcmp(valid_tests_inputs[i].relative_part, ".") == 0) {
+                       relative = cur_path;
+               } else if (strcmp(valid_tests_inputs[i].relative_part, "..") == 0) {
+                       relative = prev_path;
+               } else if (strcmp(valid_tests_inputs[i].relative_part, "../..") == 0) {
+                       relative = pprev_path;
+               } else {
+                       relative = empty;
+               }
+
+               snprintf(valid_tests_expected_results[i], PATH_MAX,
+                               "%s%s", relative, valid_tests_inputs[i].absolute_part);
+       }
+
+end:
+       free(cur_path);
+       free(prev_path);
+       free(pprev_path);
+       free(empty);
+
+       return ret;
+}
+
+static int free_valid_results(void)
+{
+       int i;
+
+       for (i = 0; i < num_valid_tests; i++) {
+               free(valid_tests_expected_results[i]);
+       }
+
+       free(valid_tests_expected_results);
+
+       return 0;
+}
+
+static int prepare_symlink_tree(void)
+{
+       int i;
+       char tmppath[PATH_MAX] = {};
+
+       /* Create the temporary directory */
+       if (mkdtemp(tree_origin) == NULL) {
+               PRINT_ERR("failed to mkdtemp");
+               goto error;
+       }
+
+       /* Create the directories of the test tree */
+       for (i = 0; i < num_tree_dirs; i++) {
+               snprintf(tmppath, sizeof(tmppath), "%s/%s", tree_origin,
+                               tree_dirs[i]);
+
+               if (mkdir(tmppath, 0755) != 0) {
+                       PRINT_ERR("mkdir failed with path \"%s\"", tmppath);
+                       goto error;
+               }
+       }
+
+       /* Create the symlinks of the test tree */
+       for (i = 0; i < num_tree_symlinks; i++) {
+               snprintf(tmppath, sizeof(tmppath), "%s/%s",
+                               tree_origin, tree_symlinks[i].orig);
+
+               if (symlink(tree_symlinks[i].dest, tmppath) != 0) {
+                       PRINT_ERR("failed to symlink \"%s\" to \"%s\"", tmppath,
+                                       tree_symlinks[i].dest);
+                       goto error;
+               }
+       }
+
+       return 0;
+
+error:
+       return 1;
+}
+
+static int free_symlink_tree(void)
+{
+       int i;
+       char tmppath[PATH_MAX];
+
+       /* Remove the symlinks from the test tree */
+       for (i =  num_tree_symlinks - 1; i > -1; i--) {
+               snprintf(tmppath, PATH_MAX, "%s/%s",
+                               tree_origin, tree_symlinks[i].orig);
+
+               if (unlink(tmppath) != 0) {
+                       PRINT_ERR("failed to unlink \"%s\"", tmppath);
+                       goto error;
+               }
+       }
+
+       /* Remove the directories from the test tree */
+       for (i = num_tree_dirs - 1; i > -1; i--) {
+               snprintf(tmppath, PATH_MAX, "%s/%s", tree_origin, tree_dirs[i]);
+
+               if (rmdir(tmppath) != 0) {
+                       PRINT_ERR("failed to rmdir \"%s\"", tmppath);
+                       goto error;
+               }
+       }
+
+       /* Remove the temporary directory */
+       if (rmdir(tree_origin) != 0) {
+               PRINT_ERR("failed to rmdir \"%s\"", tree_origin);
+               goto error;
+       }
+
+       return 0;
+
+error:
+       return 1;
+}
+
+static void test_utils_expand_path(void)
+{
+       char *result;
+       char name[100], tmppath[PATH_MAX], real_tree_origin[PATH_MAX];
+       int i, treelen;
+
+       /* Test valid cases */
+       for (i = 0; i < num_valid_tests; i++) {
+               sprintf(name, "valid test case: %s", valid_tests_inputs[i].input);
+
+               result = utils_expand_path(valid_tests_inputs[i].input);
+               ok(result != NULL &&
+                               strcmp(result, valid_tests_expected_results[i]) == 0, name);
+
+               free(result);
+       }
+
+       /*
+        * Get the realpath for the tree_origin since it can itself be a
+        * symlink.
+        */
+       result = realpath(tree_origin, real_tree_origin);
+       if (!result) {
+               fail("realpath failed.");
+               return;
+       }
+
+       /* Test symlink tree cases */
+       treelen = strlen(real_tree_origin) + 1;
+       for (i = 0; i < num_symlink_tests; i++) {
+               int ret;
+
+               sprintf(name, "symlink tree test case: [tmppath/]%s",
+                               symlink_tests_inputs[i].input);
+
+               ret = snprintf(tmppath, PATH_MAX, "%s/%s",
+                               real_tree_origin,
+                               symlink_tests_inputs[i].input);
+               if (ret == -1 || ret >= PATH_MAX) {
+                       PRINT_ERR("truncation occurred while concatenating paths \"%s\" and \"%s\"",
+                                       real_tree_origin,
+                                       symlink_tests_inputs[i].input);
+                       fail(name);
+                       continue;
+               }
+               result = utils_expand_path(tmppath);
+               ok(result != NULL && strcmp(result + treelen,
+                                       symlink_tests_inputs[i].expected_result) == 0, name);
+
+               free(result);
+       }
+
+       /* Test invalid cases */
+       for (i = 0; i < num_invalid_tests; i++) {
+               const char *test_input = invalid_tests_inputs[i];
+
+               sprintf(name, "invalid test case: %s", test_input ?
+                               test_input : "NULL");
+
+               result = utils_expand_path(test_input);
+               if (result != NULL) {
+                       free(result);
+               }
+               ok(result == NULL, name);
+       }
+}
+
+int main(int argc, char **argv)
+{
+       if (prepare_symlink_tree() != 0) {
+               goto error_mkdir;
+       }
+
+       if (prepare_valid_results() != 0) {
+               goto error_malloc;
+       }
+
+       plan_tests(num_valid_tests + num_invalid_tests + num_symlink_tests);
+
+       diag("utils_expand_path tests");
+
+       test_utils_expand_path();
+
+       free_valid_results();
+       free_symlink_tree();
+
+       return exit_status();
+
+error_malloc:
+       free_valid_results();
+
+error_mkdir:
+       free_symlink_tree();
+
+       return 1;
+}
diff --git a/tests/unit/test_utils_parse_size_suffix.c b/tests/unit/test_utils_parse_size_suffix.c
deleted file mode 100644 (file)
index 04f2fff..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (C) 2013 Simon Marchi <simon.marchi@polymtl.ca>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-#include <string.h>
-#include <stdio.h>
-
-#include <tap/tap.h>
-
-#include <common/utils.h>
-
-/* For error.h */
-int lttng_opt_quiet = 1;
-int lttng_opt_verbose = 3;
-int lttng_opt_mi;
-
-struct valid_test_input {
-       const char *input;
-       uint64_t expected_result;
-};
-
-/* Valid test cases */
-static struct valid_test_input valid_tests_inputs[] = {
-               { "0", 0 },
-               { "1234", 1234 },
-               { "0x400", 1024 },
-               { "0300", 192 },
-               { "16k", 16384 },
-               { "128K", 131072 },
-               { "0x1234k", 4771840 },
-               { "32M", 33554432 },
-               { "1024G", 1099511627776ULL },
-               { "0X400", 1024 },
-               { "0x40a", 1034 },
-               { "0X40b", 1035 },
-               { "0x40C", 1036 },
-               { "0X40D", 1037 },
-               { "0x40e", 1038 },
-               { "0X40f", 1039 },
-               { "00", 0 },
-               { "0k", 0 },
-               { "0K", 0 },
-               { "0M", 0 },
-               { "0G", 0 },
-               { "00k", 0 },
-               { "00K", 0 },
-               { "00M", 0 },
-               { "00G", 0 },
-               { "0x0", 0 },
-               { "0X0", 0 },
-               { "0x0k", 0 },
-               { "0X0K", 0 },
-               { "0x0M", 0 },
-               { "0X0G", 0 },
-               { "0X40G", 68719476736ULL },
-               { "0300k", 196608 },
-               { "0300K", 196608 },
-               { "030M", 25165824 },
-               { "020G", 17179869184ULL },
-               { "0xa0k", 163840 },
-               { "0xa0K", 163840 },
-               { "0XA0M", 167772160 },
-               { "0xA0G", 171798691840ULL },
-};
-static const int num_valid_tests = sizeof(valid_tests_inputs) / sizeof(valid_tests_inputs[0]);
-
-/* Invalid test cases */
-static const char *invalid_tests_inputs[] = {
-               "",
-               " ",
-               "-1",
-               "k",
-               "4611686018427387904G",
-               "0x40g",
-               "08",
-               "09",
-               "0x",
-               "x0",
-               "0xx0",
-               "07kK",
-               "0xk",
-               "0XM",
-               "0xG",
-               "0x0MM",
-               "0X0GG",
-               "0a",
-               "0B",
-};
-
-static const int num_invalid_tests = sizeof(invalid_tests_inputs) / sizeof(invalid_tests_inputs[0]);
-
-static void test_utils_parse_size_suffix(void)
-{
-       uint64_t result;
-       int ret;
-       int i;
-
-       /* Test valid cases */
-       for (i = 0; i < num_valid_tests; i++) {
-               char name[100];
-               sprintf(name, "valid test case: %s", valid_tests_inputs[i].input);
-
-               ret = utils_parse_size_suffix(valid_tests_inputs[i].input, &result);
-               ok(ret == 0 && result == valid_tests_inputs[i].expected_result, name);
-       }
-
-       /* Test invalid cases */
-       for (i = 0; i < num_invalid_tests; i++) {
-               char name[100];
-               sprintf(name, "invalid test case: %s", invalid_tests_inputs[i]);
-
-               ret = utils_parse_size_suffix(invalid_tests_inputs[i], &result);
-               ok(ret != 0, name);
-       }
-}
-
-int main(int argc, char **argv)
-{
-       plan_tests(num_valid_tests + num_invalid_tests);
-
-       diag("utils_parse_size_suffix tests");
-
-       test_utils_parse_size_suffix();
-
-       return exit_status();
-}
diff --git a/tests/unit/test_utils_parse_size_suffix.cpp b/tests/unit/test_utils_parse_size_suffix.cpp
new file mode 100644 (file)
index 0000000..04f2fff
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2013 Simon Marchi <simon.marchi@polymtl.ca>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#include <string.h>
+#include <stdio.h>
+
+#include <tap/tap.h>
+
+#include <common/utils.h>
+
+/* For error.h */
+int lttng_opt_quiet = 1;
+int lttng_opt_verbose = 3;
+int lttng_opt_mi;
+
+struct valid_test_input {
+       const char *input;
+       uint64_t expected_result;
+};
+
+/* Valid test cases */
+static struct valid_test_input valid_tests_inputs[] = {
+               { "0", 0 },
+               { "1234", 1234 },
+               { "0x400", 1024 },
+               { "0300", 192 },
+               { "16k", 16384 },
+               { "128K", 131072 },
+               { "0x1234k", 4771840 },
+               { "32M", 33554432 },
+               { "1024G", 1099511627776ULL },
+               { "0X400", 1024 },
+               { "0x40a", 1034 },
+               { "0X40b", 1035 },
+               { "0x40C", 1036 },
+               { "0X40D", 1037 },
+               { "0x40e", 1038 },
+               { "0X40f", 1039 },
+               { "00", 0 },
+               { "0k", 0 },
+               { "0K", 0 },
+               { "0M", 0 },
+               { "0G", 0 },
+               { "00k", 0 },
+               { "00K", 0 },
+               { "00M", 0 },
+               { "00G", 0 },
+               { "0x0", 0 },
+               { "0X0", 0 },
+               { "0x0k", 0 },
+               { "0X0K", 0 },
+               { "0x0M", 0 },
+               { "0X0G", 0 },
+               { "0X40G", 68719476736ULL },
+               { "0300k", 196608 },
+               { "0300K", 196608 },
+               { "030M", 25165824 },
+               { "020G", 17179869184ULL },
+               { "0xa0k", 163840 },
+               { "0xa0K", 163840 },
+               { "0XA0M", 167772160 },
+               { "0xA0G", 171798691840ULL },
+};
+static const int num_valid_tests = sizeof(valid_tests_inputs) / sizeof(valid_tests_inputs[0]);
+
+/* Invalid test cases */
+static const char *invalid_tests_inputs[] = {
+               "",
+               " ",
+               "-1",
+               "k",
+               "4611686018427387904G",
+               "0x40g",
+               "08",
+               "09",
+               "0x",
+               "x0",
+               "0xx0",
+               "07kK",
+               "0xk",
+               "0XM",
+               "0xG",
+               "0x0MM",
+               "0X0GG",
+               "0a",
+               "0B",
+};
+
+static const int num_invalid_tests = sizeof(invalid_tests_inputs) / sizeof(invalid_tests_inputs[0]);
+
+static void test_utils_parse_size_suffix(void)
+{
+       uint64_t result;
+       int ret;
+       int i;
+
+       /* Test valid cases */
+       for (i = 0; i < num_valid_tests; i++) {
+               char name[100];
+               sprintf(name, "valid test case: %s", valid_tests_inputs[i].input);
+
+               ret = utils_parse_size_suffix(valid_tests_inputs[i].input, &result);
+               ok(ret == 0 && result == valid_tests_inputs[i].expected_result, name);
+       }
+
+       /* Test invalid cases */
+       for (i = 0; i < num_invalid_tests; i++) {
+               char name[100];
+               sprintf(name, "invalid test case: %s", invalid_tests_inputs[i]);
+
+               ret = utils_parse_size_suffix(invalid_tests_inputs[i], &result);
+               ok(ret != 0, name);
+       }
+}
+
+int main(int argc, char **argv)
+{
+       plan_tests(num_valid_tests + num_invalid_tests);
+
+       diag("utils_parse_size_suffix tests");
+
+       test_utils_parse_size_suffix();
+
+       return exit_status();
+}
diff --git a/tests/unit/test_utils_parse_time_suffix.c b/tests/unit/test_utils_parse_time_suffix.c
deleted file mode 100644 (file)
index 95aac55..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (C) 2015 Simon Marchi <simon.marchi@polymtl.ca>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-#include <string.h>
-#include <stdio.h>
-#include <inttypes.h>
-
-#include <tap/tap.h>
-
-#include <common/utils.h>
-
-/* For error.h */
-int lttng_opt_quiet = 1;
-int lttng_opt_verbose = 3;
-int lttng_opt_mi;
-
-struct valid_test_input {
-       const char *input;
-       uint64_t expected_result;
-};
-
-/* Valid test cases */
-static struct valid_test_input valid_tests_inputs[] = {
-               { "0", 0 },
-               { "1234", 1234 },
-               { "1234us", 1234 },
-               { "16ms", 16000 },
-               { "128ms", 128000 },
-               { "32s", 32000000 },
-               { "1m", 60000000 },
-               { "20m", 1200000000 },
-               { "1h", 3600000000 },
-               { "5h", 18000000000 },
-               { "00", 0 },
-               { "0us", 0 },
-               { "0ms", 0 },
-               { "0s", 0 },
-               { "0m", 0 },
-               { "0h", 0 },
-               { "00us", 0 },
-               { "00ms", 0 },
-               { "00s", 0 },
-               { "00m", 0 },
-               { "00h", 0 },
-               { "12ms", 12000 },
-               { "3597us", 3597 },
-               { "+5", 5 },
-               { "08", 8 },
-               { "0145us", 145 },
-};
-static const int num_valid_tests = sizeof(valid_tests_inputs) / sizeof(valid_tests_inputs[0]);
-
-/* Invalid test cases */
-static const char *invalid_tests_inputs[] = {
-               "",
-               " ",
-               "-1",
-               "m",
-               "4611686018427387904s",
-               "0x40M",
-               "0x",
-               "x0",
-               "0xx0",
-               "07mm",
-               "0xm",
-               "0Xs",
-               "0x0ss",
-               "0a",
-               "0B",
-               "0x3 s",
-               "0xbs ",
-               "14ns",
-               "0xbs",
-               "14ns",
-               "14ms garbage after value",
-               "0x14s",
-               "0u",
-               "5mS",
-               "5Ms",
-               "12ussr",
-               "67msrp",
-               "14si",
-               "12mo",
-               "53hi",
-};
-static const int num_invalid_tests = sizeof(invalid_tests_inputs) / sizeof(invalid_tests_inputs[0]);
-
-static void test_utils_parse_time_suffix(void)
-{
-       uint64_t result;
-       int ret;
-       int i;
-
-       /* Test valid cases */
-       for (i = 0; i < num_valid_tests; i++) {
-               char name[256];
-
-               ret = utils_parse_time_suffix(valid_tests_inputs[i].input, &result);
-               sprintf(name, "valid test case: %s expected %" PRIu64, valid_tests_inputs[i].input, result);
-               ok(ret == 0 && result == valid_tests_inputs[i].expected_result, name);
-       }
-
-       /* Test invalid cases */
-       for (i = 0; i < num_invalid_tests; i++) {
-               char name[100];
-
-               sprintf(name, "invalid test case: %s", invalid_tests_inputs[i]);
-
-               ret = utils_parse_time_suffix(invalid_tests_inputs[i], &result);
-               ok(ret != 0, name);
-       }
-}
-
-int main(int argc, char **argv)
-{
-       plan_tests(num_valid_tests + num_invalid_tests);
-
-       diag("utils_parse_time_suffix tests");
-
-       test_utils_parse_time_suffix();
-
-       return exit_status();
-}
diff --git a/tests/unit/test_utils_parse_time_suffix.cpp b/tests/unit/test_utils_parse_time_suffix.cpp
new file mode 100644 (file)
index 0000000..95aac55
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2015 Simon Marchi <simon.marchi@polymtl.ca>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <inttypes.h>
+
+#include <tap/tap.h>
+
+#include <common/utils.h>
+
+/* For error.h */
+int lttng_opt_quiet = 1;
+int lttng_opt_verbose = 3;
+int lttng_opt_mi;
+
+struct valid_test_input {
+       const char *input;
+       uint64_t expected_result;
+};
+
+/* Valid test cases */
+static struct valid_test_input valid_tests_inputs[] = {
+               { "0", 0 },
+               { "1234", 1234 },
+               { "1234us", 1234 },
+               { "16ms", 16000 },
+               { "128ms", 128000 },
+               { "32s", 32000000 },
+               { "1m", 60000000 },
+               { "20m", 1200000000 },
+               { "1h", 3600000000 },
+               { "5h", 18000000000 },
+               { "00", 0 },
+               { "0us", 0 },
+               { "0ms", 0 },
+               { "0s", 0 },
+               { "0m", 0 },
+               { "0h", 0 },
+               { "00us", 0 },
+               { "00ms", 0 },
+               { "00s", 0 },
+               { "00m", 0 },
+               { "00h", 0 },
+               { "12ms", 12000 },
+               { "3597us", 3597 },
+               { "+5", 5 },
+               { "08", 8 },
+               { "0145us", 145 },
+};
+static const int num_valid_tests = sizeof(valid_tests_inputs) / sizeof(valid_tests_inputs[0]);
+
+/* Invalid test cases */
+static const char *invalid_tests_inputs[] = {
+               "",
+               " ",
+               "-1",
+               "m",
+               "4611686018427387904s",
+               "0x40M",
+               "0x",
+               "x0",
+               "0xx0",
+               "07mm",
+               "0xm",
+               "0Xs",
+               "0x0ss",
+               "0a",
+               "0B",
+               "0x3 s",
+               "0xbs ",
+               "14ns",
+               "0xbs",
+               "14ns",
+               "14ms garbage after value",
+               "0x14s",
+               "0u",
+               "5mS",
+               "5Ms",
+               "12ussr",
+               "67msrp",
+               "14si",
+               "12mo",
+               "53hi",
+};
+static const int num_invalid_tests = sizeof(invalid_tests_inputs) / sizeof(invalid_tests_inputs[0]);
+
+static void test_utils_parse_time_suffix(void)
+{
+       uint64_t result;
+       int ret;
+       int i;
+
+       /* Test valid cases */
+       for (i = 0; i < num_valid_tests; i++) {
+               char name[256];
+
+               ret = utils_parse_time_suffix(valid_tests_inputs[i].input, &result);
+               sprintf(name, "valid test case: %s expected %" PRIu64, valid_tests_inputs[i].input, result);
+               ok(ret == 0 && result == valid_tests_inputs[i].expected_result, name);
+       }
+
+       /* Test invalid cases */
+       for (i = 0; i < num_invalid_tests; i++) {
+               char name[100];
+
+               sprintf(name, "invalid test case: %s", invalid_tests_inputs[i]);
+
+               ret = utils_parse_time_suffix(invalid_tests_inputs[i], &result);
+               ok(ret != 0, name);
+       }
+}
+
+int main(int argc, char **argv)
+{
+       plan_tests(num_valid_tests + num_invalid_tests);
+
+       diag("utils_parse_time_suffix tests");
+
+       test_utils_parse_time_suffix();
+
+       return exit_status();
+}
diff --git a/tests/unit/test_uuid.c b/tests/unit/test_uuid.c
deleted file mode 100644 (file)
index e13a097..0000000
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * Copyright 2019 Michael Jeanson <mjeanson@efficios.com>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-#include <stdio.h>
-#include <stdbool.h>
-#include <string.h>
-
-#include <tap/tap.h>
-
-#include "common/uuid.h"
-
-#define NR_TESTS 21
-
-static const char valid_str_1[] = "3d260c88-75ea-47b8-a7e2-d6077c0378d9";
-static const char valid_str_2[] = "611cf3a6-a68b-4515-834f-208bc2762592";
-static const char valid_str_3[] = "1b4855cc-96de-4ae8-abe3-86449c2a43c4";
-static const char valid_str_4[] = "8ADED5B9-ACD2-439F-A60C-897403AA2AB4";
-static const char valid_str_5[] = "f109e0a2-C619-4d18-b760-20EA20E0F69A";
-
-static lttng_uuid valid_uuid_1 = {
-       0x3d, 0x26, 0x0c, 0x88, 0x75, 0xea, 0x47, 0xb8,
-       0xa7, 0xe2, 0xd6, 0x07, 0x7c, 0x03, 0x78, 0xd9
-};
-static lttng_uuid valid_uuid_2 = {
-       0x61, 0x1c, 0xf3, 0xa6, 0xa6, 0x8b, 0x45, 0x15,
-       0x83, 0x4f, 0x20, 0x8b, 0xc2, 0x76, 0x25, 0x92
-};
-static lttng_uuid valid_uuid_3 = {
-       0x1b, 0x48, 0x55, 0xcc, 0x96, 0xde, 0x4a, 0xe8,
-       0xab, 0xe3, 0x86, 0x44, 0x9c, 0x2a, 0x43, 0xc4
-};
-
-static const char invalid_str_1[] = "1b485!cc-96de-4XX8-abe3-86449c2a43?4";
-static const char invalid_str_2[] = "c2e6eddb&3955&4006&be3a&70bb63bd5f25";
-static const char invalid_str_3[] = "81b1cb88-ff42-45b9-ba4d-964088ee45";
-static const char invalid_str_4[] = "2d-6c6d756574-470e-9142-a4e6ad03f143";
-static const char invalid_str_5[] = "4542ad19-9e4f-4931-8261-2101c3e089ae7";
-static const char invalid_str_6[] = "XX0123";
-
-static
-void run_test_lttng_uuid_from_str(void)
-{
-       int ret;
-       lttng_uuid uuid1;
-
-       /*
-        * Parse valid UUID strings, expect success.
-        */
-       ret = lttng_uuid_from_str(valid_str_1, uuid1);
-       ok(ret == 0, "lttng_uuid_from_str - Parse valid string '%s', expect success", valid_str_1);
-
-       ret = lttng_uuid_from_str(valid_str_2, uuid1);
-       ok(ret == 0, "lttng_uuid_from_str - Parse valid string '%s', expect success", valid_str_2);
-
-       ret = lttng_uuid_from_str(valid_str_3, uuid1);
-       ok(ret == 0, "lttng_uuid_from_str - Parse valid string '%s', expect success", valid_str_3);
-
-       ret = lttng_uuid_from_str(valid_str_4, uuid1);
-       ok(ret == 0, "lttng_uuid_from_str - Parse valid string '%s', expect success", valid_str_4);
-
-       ret = lttng_uuid_from_str(valid_str_5, uuid1);
-       ok(ret == 0, "lttng_uuid_from_str - Parse valid string '%s', expect success", valid_str_5);
-
-       /*
-        * Parse invalid UUID strings, expect failure.
-        */
-       ret = lttng_uuid_from_str(invalid_str_1, uuid1);
-       ok(ret != 0, "lttng_uuid_from_str - Parse invalid string '%s', expect failure", invalid_str_1);
-
-       ret = lttng_uuid_from_str(invalid_str_2, uuid1);
-       ok(ret != 0, "lttng_uuid_from_str - Parse invalid string '%s', expect failure", invalid_str_2);
-
-       ret = lttng_uuid_from_str(invalid_str_3, uuid1);
-       ok(ret != 0, "lttng_uuid_from_str - Parse invalid string '%s', expect failure", invalid_str_3);
-
-       ret = lttng_uuid_from_str(invalid_str_4, uuid1);
-       ok(ret != 0, "lttng_uuid_from_str - Parse invalid string '%s', expect failure", invalid_str_4);
-
-       ret = lttng_uuid_from_str(invalid_str_5, uuid1);
-       ok(ret != 0, "lttng_uuid_from_str - Parse invalid string '%s', expect failure", invalid_str_5);
-
-       ret = lttng_uuid_from_str(invalid_str_6, uuid1);
-       ok(ret != 0, "lttng_uuid_from_str - Parse invalid string '%s', expect failure", invalid_str_6);
-}
-
-static
-void run_test_lttng_uuid_to_str(void)
-{
-       char uuid_str[LTTNG_UUID_STR_LEN];
-
-       lttng_uuid_to_str(valid_uuid_1, uuid_str);
-       ok(strcmp(uuid_str, valid_str_1) == 0, "lttng_uuid_to_str - Convert UUID '%s' to string, expect success", valid_str_1);
-
-       lttng_uuid_to_str(valid_uuid_2, uuid_str);
-       ok(strcmp(uuid_str, valid_str_2) == 0, "lttng_uuid_to_str - Convert UUID '%s' to string, expect success", valid_str_2);
-
-       lttng_uuid_to_str(valid_uuid_3, uuid_str);
-       ok(strcmp(uuid_str, valid_str_3) == 0, "lttng_uuid_to_str - Convert UUID '%s' to string, expect success", valid_str_3);
-}
-
-static
-void run_test_lttng_uuid_is_equal(void)
-{
-       int ret;
-       lttng_uuid uuid1, uuid2;
-
-       lttng_uuid_from_str(valid_str_1, uuid1);
-       lttng_uuid_from_str(valid_str_1, uuid2);
-       ret = lttng_uuid_is_equal(uuid1, uuid2);
-       ok(ret == true, "lttng_uuid_is_equal - Compare same UUID, expect success");
-
-       lttng_uuid_from_str(valid_str_2, uuid2);
-       ret = lttng_uuid_is_equal(uuid1, uuid2);
-       ok(ret == false, "lttng_uuid_is_equal - Compare different UUID, expect failure");
-}
-
-static
-void run_test_lttng_uuid_copy(void)
-{
-       int ret;
-       lttng_uuid uuid1;
-
-       lttng_uuid_copy(uuid1, valid_uuid_1);
-       ret = lttng_uuid_is_equal(uuid1, valid_uuid_1);
-
-       ok(ret == true, "lttng_uuid_copy - Compare copied UUID with source, expect success");
-}
-
-static
-void run_test_lttng_uuid_generate(void)
-{
-       int ret;
-       lttng_uuid uuid1, uuid2;
-
-       lttng_uuid_generate(uuid1);
-       lttng_uuid_generate(uuid2);
-
-       ok(lttng_uuid_is_equal(uuid1, uuid2) == false, "lttng_uuid_generate - Generated UUIDs are different");
-
-       /*
-        * Set the two most significant bits (bits 6 and 7) of the
-        * clock_seq_hi_and_reserved to zero and one, respectively.
-        */
-       ret = uuid1[8] & (1 << 6);
-       ok(ret == 0, "lttng_uuid_generate - bit 6 of clock_seq_hi_and_reserved is set to zero");
-
-       ret = uuid1[8] & (1 << 7);
-       ok(ret != 0, "lttng_uuid_generate - bit 7 of clock_seq_hi_and_reserved is set to one");
-
-       /*
-        * Set the four most significant bits (bits 12 through 15) of the
-        * time_hi_and_version field to the 4-bit version number from
-        * Section 4.1.3.
-        */
-       ret = uuid1[6] >> 4;
-       ok(ret == LTTNG_UUID_VER, "lttng_uuid_generate - Generated UUID version check");
-}
-
-static
-void run_test(void)
-{
-       plan_tests(NR_TESTS);
-
-       run_test_lttng_uuid_from_str();
-       run_test_lttng_uuid_to_str();
-       run_test_lttng_uuid_is_equal();
-       run_test_lttng_uuid_copy();
-       run_test_lttng_uuid_generate();
-}
-
-int main(int argc, char **argv)
-{
-       /* Run tap-formated tests */
-       run_test();
-
-       return exit_status();
-}
diff --git a/tests/unit/test_uuid.cpp b/tests/unit/test_uuid.cpp
new file mode 100644 (file)
index 0000000..e13a097
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * Copyright 2019 Michael Jeanson <mjeanson@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#include <stdio.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include <tap/tap.h>
+
+#include "common/uuid.h"
+
+#define NR_TESTS 21
+
+static const char valid_str_1[] = "3d260c88-75ea-47b8-a7e2-d6077c0378d9";
+static const char valid_str_2[] = "611cf3a6-a68b-4515-834f-208bc2762592";
+static const char valid_str_3[] = "1b4855cc-96de-4ae8-abe3-86449c2a43c4";
+static const char valid_str_4[] = "8ADED5B9-ACD2-439F-A60C-897403AA2AB4";
+static const char valid_str_5[] = "f109e0a2-C619-4d18-b760-20EA20E0F69A";
+
+static lttng_uuid valid_uuid_1 = {
+       0x3d, 0x26, 0x0c, 0x88, 0x75, 0xea, 0x47, 0xb8,
+       0xa7, 0xe2, 0xd6, 0x07, 0x7c, 0x03, 0x78, 0xd9
+};
+static lttng_uuid valid_uuid_2 = {
+       0x61, 0x1c, 0xf3, 0xa6, 0xa6, 0x8b, 0x45, 0x15,
+       0x83, 0x4f, 0x20, 0x8b, 0xc2, 0x76, 0x25, 0x92
+};
+static lttng_uuid valid_uuid_3 = {
+       0x1b, 0x48, 0x55, 0xcc, 0x96, 0xde, 0x4a, 0xe8,
+       0xab, 0xe3, 0x86, 0x44, 0x9c, 0x2a, 0x43, 0xc4
+};
+
+static const char invalid_str_1[] = "1b485!cc-96de-4XX8-abe3-86449c2a43?4";
+static const char invalid_str_2[] = "c2e6eddb&3955&4006&be3a&70bb63bd5f25";
+static const char invalid_str_3[] = "81b1cb88-ff42-45b9-ba4d-964088ee45";
+static const char invalid_str_4[] = "2d-6c6d756574-470e-9142-a4e6ad03f143";
+static const char invalid_str_5[] = "4542ad19-9e4f-4931-8261-2101c3e089ae7";
+static const char invalid_str_6[] = "XX0123";
+
+static
+void run_test_lttng_uuid_from_str(void)
+{
+       int ret;
+       lttng_uuid uuid1;
+
+       /*
+        * Parse valid UUID strings, expect success.
+        */
+       ret = lttng_uuid_from_str(valid_str_1, uuid1);
+       ok(ret == 0, "lttng_uuid_from_str - Parse valid string '%s', expect success", valid_str_1);
+
+       ret = lttng_uuid_from_str(valid_str_2, uuid1);
+       ok(ret == 0, "lttng_uuid_from_str - Parse valid string '%s', expect success", valid_str_2);
+
+       ret = lttng_uuid_from_str(valid_str_3, uuid1);
+       ok(ret == 0, "lttng_uuid_from_str - Parse valid string '%s', expect success", valid_str_3);
+
+       ret = lttng_uuid_from_str(valid_str_4, uuid1);
+       ok(ret == 0, "lttng_uuid_from_str - Parse valid string '%s', expect success", valid_str_4);
+
+       ret = lttng_uuid_from_str(valid_str_5, uuid1);
+       ok(ret == 0, "lttng_uuid_from_str - Parse valid string '%s', expect success", valid_str_5);
+
+       /*
+        * Parse invalid UUID strings, expect failure.
+        */
+       ret = lttng_uuid_from_str(invalid_str_1, uuid1);
+       ok(ret != 0, "lttng_uuid_from_str - Parse invalid string '%s', expect failure", invalid_str_1);
+
+       ret = lttng_uuid_from_str(invalid_str_2, uuid1);
+       ok(ret != 0, "lttng_uuid_from_str - Parse invalid string '%s', expect failure", invalid_str_2);
+
+       ret = lttng_uuid_from_str(invalid_str_3, uuid1);
+       ok(ret != 0, "lttng_uuid_from_str - Parse invalid string '%s', expect failure", invalid_str_3);
+
+       ret = lttng_uuid_from_str(invalid_str_4, uuid1);
+       ok(ret != 0, "lttng_uuid_from_str - Parse invalid string '%s', expect failure", invalid_str_4);
+
+       ret = lttng_uuid_from_str(invalid_str_5, uuid1);
+       ok(ret != 0, "lttng_uuid_from_str - Parse invalid string '%s', expect failure", invalid_str_5);
+
+       ret = lttng_uuid_from_str(invalid_str_6, uuid1);
+       ok(ret != 0, "lttng_uuid_from_str - Parse invalid string '%s', expect failure", invalid_str_6);
+}
+
+static
+void run_test_lttng_uuid_to_str(void)
+{
+       char uuid_str[LTTNG_UUID_STR_LEN];
+
+       lttng_uuid_to_str(valid_uuid_1, uuid_str);
+       ok(strcmp(uuid_str, valid_str_1) == 0, "lttng_uuid_to_str - Convert UUID '%s' to string, expect success", valid_str_1);
+
+       lttng_uuid_to_str(valid_uuid_2, uuid_str);
+       ok(strcmp(uuid_str, valid_str_2) == 0, "lttng_uuid_to_str - Convert UUID '%s' to string, expect success", valid_str_2);
+
+       lttng_uuid_to_str(valid_uuid_3, uuid_str);
+       ok(strcmp(uuid_str, valid_str_3) == 0, "lttng_uuid_to_str - Convert UUID '%s' to string, expect success", valid_str_3);
+}
+
+static
+void run_test_lttng_uuid_is_equal(void)
+{
+       int ret;
+       lttng_uuid uuid1, uuid2;
+
+       lttng_uuid_from_str(valid_str_1, uuid1);
+       lttng_uuid_from_str(valid_str_1, uuid2);
+       ret = lttng_uuid_is_equal(uuid1, uuid2);
+       ok(ret == true, "lttng_uuid_is_equal - Compare same UUID, expect success");
+
+       lttng_uuid_from_str(valid_str_2, uuid2);
+       ret = lttng_uuid_is_equal(uuid1, uuid2);
+       ok(ret == false, "lttng_uuid_is_equal - Compare different UUID, expect failure");
+}
+
+static
+void run_test_lttng_uuid_copy(void)
+{
+       int ret;
+       lttng_uuid uuid1;
+
+       lttng_uuid_copy(uuid1, valid_uuid_1);
+       ret = lttng_uuid_is_equal(uuid1, valid_uuid_1);
+
+       ok(ret == true, "lttng_uuid_copy - Compare copied UUID with source, expect success");
+}
+
+static
+void run_test_lttng_uuid_generate(void)
+{
+       int ret;
+       lttng_uuid uuid1, uuid2;
+
+       lttng_uuid_generate(uuid1);
+       lttng_uuid_generate(uuid2);
+
+       ok(lttng_uuid_is_equal(uuid1, uuid2) == false, "lttng_uuid_generate - Generated UUIDs are different");
+
+       /*
+        * Set the two most significant bits (bits 6 and 7) of the
+        * clock_seq_hi_and_reserved to zero and one, respectively.
+        */
+       ret = uuid1[8] & (1 << 6);
+       ok(ret == 0, "lttng_uuid_generate - bit 6 of clock_seq_hi_and_reserved is set to zero");
+
+       ret = uuid1[8] & (1 << 7);
+       ok(ret != 0, "lttng_uuid_generate - bit 7 of clock_seq_hi_and_reserved is set to one");
+
+       /*
+        * Set the four most significant bits (bits 12 through 15) of the
+        * time_hi_and_version field to the 4-bit version number from
+        * Section 4.1.3.
+        */
+       ret = uuid1[6] >> 4;
+       ok(ret == LTTNG_UUID_VER, "lttng_uuid_generate - Generated UUID version check");
+}
+
+static
+void run_test(void)
+{
+       plan_tests(NR_TESTS);
+
+       run_test_lttng_uuid_from_str();
+       run_test_lttng_uuid_to_str();
+       run_test_lttng_uuid_is_equal();
+       run_test_lttng_uuid_copy();
+       run_test_lttng_uuid_generate();
+}
+
+int main(int argc, char **argv)
+{
+       /* Run tap-formated tests */
+       run_test();
+
+       return exit_status();
+}
This page took 0.237055 seconds and 4 git commands to generate.