/tests/lib/test_trace_ir_ref
/tests/lib/test_simple_sink
/tests/lib/test_remove_destruction_listener_in_destruction_listener
+/tests/lib/conds/conds-triggers
/tests/param-validation/test_param_validation
/tests/plugins/flt.lttng-utils.debug-info/test_bin_info
/tests/plugins/flt.lttng-utils.debug-info/test_dwarf
AS_IF([test "x$BABELTRACE_DEV_MODE" = x1], [
AC_DEFINE([BT_DEV_MODE], 1, [Babeltrace developer mode])
], [BABELTRACE_DEV_MODE=0])
+AM_CONDITIONAL([DEV_MODE], [test "x$BABELTRACE_DEV_MODE" = x1])
# BABELTRACE_DEBUG_MODE:
AC_ARG_VAR([BABELTRACE_DEBUG_MODE], [Set to 1 to enable the Babeltrace debug mode (enables internal assertions for Babeltrace maintainers)])
tests/ctf-writer/Makefile
tests/lib/Makefile
tests/lib/test-plugin-plugins/Makefile
+ tests/lib/conds/Makefile
tests/Makefile
tests/param-validation/Makefile
tests/plugins/Makefile
if HAVE_PYTHON
TESTS_PLUGINS += plugins/src.ctf.lttng-live/test_live
+
+if DEV_MODE
+TESTS_LIB += lib/conds/test_conds
+endif
endif
TESTS_PYTHON_PLUGIN_PROVIDER =
endif
dist_check_SCRIPTS = test_plugin
+
+if HAVE_PYTHON
+if DEV_MODE
+SUBDIRS += conds
+endif
+endif
--- /dev/null
+# SPDX-License-Identifier: MIT
+
+AM_CPPFLAGS += -I$(top_srcdir)/tests/utils
+
+conds_triggers_SOURCES = conds-triggers.c utils.c utils.h
+conds_triggers_LDADD = \
+ $(top_builddir)/src/common/libbabeltrace2-common.la \
+ $(top_builddir)/src/logging/libbabeltrace2-logging.la \
+ $(top_builddir)/src/lib/libbabeltrace2.la
+
+noinst_PROGRAMS = conds-triggers
+
+dist_check_SCRIPTS = test_conds test.py
--- /dev/null
+/*
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ * Copyright (C) 2020 Philippe Proulx <pproulx@efficios.com>
+ */
+
+#include <babeltrace2/babeltrace.h>
+
+#include "common/assert.h"
+#include "utils.h"
+
+static
+bt_field_class *get_uint_fc(bt_self_component *self_comp)
+{
+ bt_trace_class *tc = bt_trace_class_create(self_comp);
+ bt_field_class *fc;
+
+ BT_ASSERT(tc);
+ fc = bt_field_class_integer_unsigned_create(tc);
+ BT_ASSERT(fc);
+ return fc;
+}
+
+static
+void trigger_fc_int_set_field_value_range_n_0(bt_self_component *self_comp)
+{
+ bt_field_class_integer_set_field_value_range(get_uint_fc(self_comp), 0);
+}
+
+static
+void trigger_fc_int_set_field_value_range_n_gt_64(bt_self_component *self_comp)
+{
+ bt_field_class_integer_set_field_value_range(get_uint_fc(self_comp),
+ 65);
+}
+
+static
+void trigger_fc_int_set_field_value_range_null(bt_self_component *self_comp)
+{
+ bt_field_class_integer_set_field_value_range(NULL, 23);
+}
+
+static
+const struct cond_trigger triggers[] = {
+ COND_TRIGGER_PRE_RUN_IN_COMP_CLS_INIT(
+ "pre:field-class-integer-set-field-value-range:valid-n",
+ "0",
+ trigger_fc_int_set_field_value_range_n_0
+ ),
+ COND_TRIGGER_PRE_RUN_IN_COMP_CLS_INIT(
+ "pre:field-class-integer-set-field-value-range:valid-n",
+ "gt-64",
+ trigger_fc_int_set_field_value_range_n_gt_64
+ ),
+ COND_TRIGGER_PRE_RUN_IN_COMP_CLS_INIT(
+ "pre:field-class-integer-set-field-value-range:not-null:field-class",
+ NULL,
+ trigger_fc_int_set_field_value_range_null
+ ),
+};
+
+int main(int argc, const char *argv[])
+{
+ cond_main(argc, argv, triggers, sizeof(triggers) / sizeof(*triggers));
+ return 0;
+}
--- /dev/null
+# SPDX-License-Identifier: MIT
+#
+# Copyright (c) 2020 Philippe Proulx <pproulx@efficios.com>
+
+import unittest
+import subprocess
+import functools
+import signal
+import os
+import os.path
+import re
+import json
+
+
+# the `conds-triggers` program's full path
+_CONDS_TRIGGERS_PATH = os.environ['BT_TESTS_LIB_CONDS_TRIGGER_BIN']
+
+
+# test methods are added by _create_tests()
+class LibPrePostCondsTestCase(unittest.TestCase):
+ pass
+
+
+# a condition trigger descriptor (base)
+class _CondTriggerDescriptor:
+ def __init__(self, index, trigger_name, cond_id):
+ self._index = index
+ self._trigger_name = trigger_name
+ self._cond_id = cond_id
+
+ @property
+ def index(self):
+ return self._index
+
+ @property
+ def trigger_name(self):
+ return self._trigger_name
+
+ @property
+ def cond_id(self):
+ return self._cond_id
+
+
+# precondition trigger descriptor
+class _PreCondTriggerDescriptor(_CondTriggerDescriptor):
+ @property
+ def type_str(self):
+ return 'pre'
+
+
+# postcondition trigger descriptor
+class _PostCondTriggerDescriptor(_CondTriggerDescriptor):
+ @property
+ def type_str(self):
+ return 'post'
+
+
+# test method template for `LibPrePostCondsTestCase`
+def _test(self, descriptor):
+ # Execute:
+ #
+ # $ conds-triggers run <index>
+ #
+ # where `<index>` is the descriptor's index.
+ with subprocess.Popen(
+ [_CONDS_TRIGGERS_PATH, 'run', str(descriptor.index)],
+ stderr=subprocess.PIPE,
+ universal_newlines=True,
+ ) as proc:
+ # wait for termination and get standard output/error data
+ timeout = 5
+
+ try:
+ # wait for program end and get standard error pipe's contents
+ _, stderr = proc.communicate(timeout=timeout)
+ except subprocess.TimeoutExpired:
+ self.fail('Process hanged for {} seconds'.format(timeout))
+ return
+
+ # assert that program aborted (only available on POSIX)
+ if os.name == 'posix':
+ self.assertEqual(proc.returncode, -int(signal.SIGABRT))
+
+ # assert that the standard error text contains the condition ID
+ text = 'Condition ID: `{}`.'.format(descriptor.cond_id)
+ self.assertIn(text, stderr)
+
+
+# Condition trigger descriptors from the JSON array returned by
+#
+# $ conds-triggers list
+def _cond_trigger_descriptors_from_json(json_descr_array):
+ descriptors = []
+ descriptor_names = set()
+
+ for index, json_descr in enumerate(json_descr_array):
+ # sanity check: check for duplicate
+ trigger_name = json_descr['name']
+
+ if trigger_name in descriptor_names:
+ raise ValueError(
+ 'Duplicate condition trigger name `{}`'.format(trigger_name)
+ )
+
+ # condition ID
+ cond_id = json_descr['cond-id']
+
+ if cond_id.startswith('pre'):
+ cond_type = _PreCondTriggerDescriptor
+ elif cond_id.startswith('post'):
+ cond_type = _PostCondTriggerDescriptor
+ else:
+ raise ValueError('Invalid condition ID `{}`'.format(cond_id))
+
+ descriptors.append(cond_type(index, trigger_name, cond_id))
+ descriptor_names.add(trigger_name)
+
+ return descriptors
+
+
+# creates the individual tests of `LibPrePostCondsTestCase`
+def _create_tests():
+ # Execute `conds-triggers list` to get a JSON array of condition
+ # trigger descriptors.
+ json_descr_array = json.loads(
+ subprocess.check_output([_CONDS_TRIGGERS_PATH, 'list'], universal_newlines=True)
+ )
+
+ # get condition trigger descriptor objects from JSON
+ descriptors = _cond_trigger_descriptors_from_json(json_descr_array)
+
+ # create test methods
+ for descriptor in descriptors:
+ # test method name
+ test_meth_name = 'test_{}'.format(
+ re.sub(r'[^a-zA-Z0-9_]', '_', descriptor.trigger_name)
+ )
+
+ # test method
+ meth = functools.partialmethod(_test, descriptor)
+ setattr(LibPrePostCondsTestCase, test_meth_name, meth)
+
+
+_create_tests()
+
+
+if __name__ == '__main__':
+ unittest.main()
--- /dev/null
+#!/bin/bash
+#
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Copyright (C) 2020 Philippe Proulx <pproulx@efficios.com>
+
+if [ "x${BT_TESTS_SRCDIR:-}" != "x" ]; then
+ UTILSSH="$BT_TESTS_SRCDIR/utils/utils.sh"
+else
+ UTILSSH="$(dirname "$0")/../../utils/utils.sh"
+fi
+
+# shellcheck source=../../utils/utils.sh
+source "$UTILSSH"
+
+reldir=lib/conds
+export BT_TESTS_LIB_CONDS_TRIGGER_BIN="$BT_TESTS_BUILDDIR/$reldir/conds-triggers"
+
+if [ "$BT_OS_TYPE" = "mingw" ]; then
+ BT_TESTS_LIB_CONDS_TRIGGER_BIN="$BT_TESTS_LIB_CONDS_TRIGGER_BIN.exe"
+fi
+
+run_python_bt2_test "$BT_TESTS_SRCDIR/$reldir" test.py
--- /dev/null
+/*
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ * Copyright (C) 2020 Philippe Proulx <pproulx@efficios.com>
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <babeltrace2/babeltrace.h>
+#include <glib.h>
+
+#include "common/assert.h"
+#include "utils.h"
+
+typedef void (* run_in_comp_cls_init_func)(
+ bt_self_component *self_comp, void *user_data);
+
+struct comp_cls_init_method_data {
+ run_in_comp_cls_init_func func;
+ void *user_data;
+};
+
+static
+bt_component_class_initialize_method_status comp_cls_init(
+ bt_self_component_source *self_comp,
+ bt_self_component_source_configuration *conf,
+ const bt_value *params, void *init_method_data)
+{
+ struct comp_cls_init_method_data *data = init_method_data;
+
+ /* Call user function which is expected to abort */
+ data->func(bt_self_component_source_as_self_component(self_comp),
+ data->user_data);
+
+ /* Never reached! */
+ return BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_ERROR;
+}
+
+static
+bt_message_iterator_class_next_method_status msg_iter_cls_next(
+ bt_self_message_iterator *self_msg_iter,
+ bt_message_array_const msgs, uint64_t capacity,
+ uint64_t *count)
+{
+ /* Not used */
+ return BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_ERROR;
+}
+
+static
+void run_in_comp_cls_init(run_in_comp_cls_init_func func,
+ void *user_data)
+{
+ bt_message_iterator_class *msg_iter_cls;
+ bt_component_class_source *comp_cls;
+ bt_component_class_set_method_status set_method_status;
+ bt_graph *graph;
+ struct comp_cls_init_method_data init_method_data = {
+ .func = func,
+ .user_data = user_data,
+ };
+
+ /* Create component class */
+ msg_iter_cls = bt_message_iterator_class_create(msg_iter_cls_next);
+ BT_ASSERT(msg_iter_cls);
+ comp_cls = bt_component_class_source_create("yo", msg_iter_cls);
+ BT_ASSERT(comp_cls);
+ set_method_status = bt_component_class_source_set_initialize_method(
+ comp_cls, comp_cls_init);
+ BT_ASSERT(set_method_status == BT_COMPONENT_CLASS_SET_METHOD_STATUS_OK);
+
+ /* Create graph */
+ graph = bt_graph_create(0);
+ BT_ASSERT(graph);
+
+ /*
+ * Add source component: this calls the initialization method,
+ * calling `func`.
+ */
+ (void) bt_graph_add_source_component_with_initialize_method_data(graph,
+ comp_cls, "whatever", NULL, &init_method_data,
+ BT_LOGGING_LEVEL_NONE, NULL);
+
+ /*
+ * This point is not expected to be reached as func() is
+ * expected to abort.
+ */
+}
+
+static
+void run_in_comp_cls_init_defer(bt_self_component *self_comp,
+ void *user_data)
+{
+ cond_trigger_run_in_comp_cls_init_func user_func = user_data;
+
+ user_func(self_comp);
+}
+
+static
+void run_trigger(const struct cond_trigger *trigger)
+{
+ switch (trigger->func_type) {
+ case COND_TRIGGER_FUNC_TYPE_BASIC:
+ trigger->func.basic();
+ break;
+ case COND_TRIGGER_FUNC_TYPE_RUN_IN_COMP_CLS_INIT:
+ run_in_comp_cls_init(run_in_comp_cls_init_defer,
+ trigger->func.run_in_comp_cls_init);
+ break;
+ default:
+ abort();
+ }
+}
+
+static
+void escape_json_string(const char *str, GString *escaped_str)
+{
+ g_string_assign(escaped_str, "");
+
+ for (const char *ch = str; *ch; ch++) {
+ if (*ch == '\\' || *ch == '"') {
+ g_string_append_c(escaped_str, '\\');
+ }
+
+ g_string_append_c(escaped_str, *ch);
+ }
+}
+
+static
+void list_triggers(const struct cond_trigger triggers[], size_t trigger_count)
+{
+ GString *escaped_str = g_string_new(NULL);
+ size_t i;
+
+ BT_ASSERT(escaped_str);
+ printf("[");
+
+ for (i = 0; i < trigger_count; i++) {
+ const struct cond_trigger *trigger = &triggers[i];
+
+ /* Condition ID */
+ escape_json_string(trigger->cond_id, escaped_str);
+ printf("{\"cond-id\":\"%s\",", escaped_str->str);
+
+ /* Name starts with condition ID */
+ printf("\"name\":\"%s", escaped_str->str);
+
+ if (trigger->suffix) {
+ escape_json_string(trigger->suffix, escaped_str);
+ printf("-%s", escaped_str->str);
+ }
+
+ printf("\"}");
+
+ if (i < trigger_count - 1) {
+ /* Comma between objects */
+ printf(",");
+ }
+ }
+
+ printf("]");
+ g_string_free(escaped_str, TRUE);
+ fflush(stdout);
+}
+
+void cond_main(int argc, const char *argv[],
+ const struct cond_trigger triggers[], size_t trigger_count)
+{
+ BT_ASSERT(argc >= 2);
+
+ if (strcmp(argv[1], "list") == 0) {
+ list_triggers(triggers, trigger_count);
+ } else if (strcmp(argv[1], "run") == 0) {
+ int index;
+
+ BT_ASSERT(argc >= 3);
+ index = atoi(argv[2]);
+ BT_ASSERT(index >= 0 && index < trigger_count);
+ run_trigger(&triggers[index]);
+ }
+}
--- /dev/null
+/*
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ * Copyright (C) 2020 Philippe Proulx <pproulx@efficios.com>
+ */
+
+#ifndef TESTS_LIB_CONDS_UTILS_H
+#define TESTS_LIB_CONDS_UTILS_H
+
+enum cond_trigger_func_type {
+ COND_TRIGGER_FUNC_TYPE_BASIC,
+ COND_TRIGGER_FUNC_TYPE_RUN_IN_COMP_CLS_INIT,
+};
+
+enum cond_trigger_type {
+ COND_TRIGGER_TYPE_PRE,
+ COND_TRIGGER_TYPE_POST,
+};
+
+typedef void (* cond_trigger_basic_func)(void);
+typedef void (* cond_trigger_run_in_comp_cls_init_func)(bt_self_component *);
+
+struct cond_trigger {
+ enum cond_trigger_type type;
+ enum cond_trigger_func_type func_type;
+ const char *cond_id;
+ const char *suffix;
+ union {
+ cond_trigger_basic_func basic;
+ cond_trigger_run_in_comp_cls_init_func run_in_comp_cls_init;
+ } func;
+};
+
+#define COND_TRIGGER_PRE_BASIC(_cond_id, _suffix, _func) \
+ { \
+ .type = COND_TRIGGER_TYPE_PRE, \
+ .func_type = COND_TRIGGER_FUNC_TYPE_BASIC, \
+ .cond_id = _cond_id, \
+ .suffix = _suffix, \
+ .func = { \
+ .basic = _func, \
+ } \
+ }
+
+#define COND_TRIGGER_POST_BASIC(_cond_id, _suffix, _func) \
+ { \
+ .type = COND_TRIGGER_TYPE_POST, \
+ .func_type = COND_TRIGGER_FUNC_TYPE_BASIC, \
+ .cond_id = _cond_id, \
+ .suffix = _suffix, \
+ .func = { \
+ .basic = _func, \
+ } \
+ }
+
+#define COND_TRIGGER_PRE_RUN_IN_COMP_CLS_INIT(_cond_id, _suffix, _func) \
+ { \
+ .type = COND_TRIGGER_TYPE_PRE, \
+ .func_type = COND_TRIGGER_FUNC_TYPE_RUN_IN_COMP_CLS_INIT, \
+ .cond_id = _cond_id, \
+ .suffix = _suffix, \
+ .func = { \
+ .run_in_comp_cls_init = _func, \
+ } \
+ }
+
+#define COND_TRIGGER_POST_RUN_IN_COMP_CLS_INIT(_cond_id, _suffix, _func) \
+ { \
+ .type = COND_TRIGGER_TYPE_POST, \
+ .func_type = COND_TRIGGER_FUNC_TYPE_RUN_IN_COMP_CLS_INIT, \
+ .cond_id = _cond_id, \
+ .suffix = _suffix, \
+ .func = { \
+ .run_in_comp_cls_init = _func, \
+ } \
+ }
+
+void cond_main(int argc, const char *argv[],
+ const struct cond_trigger triggers[],
+ size_t trigger_count);
+
+#endif /* TESTS_LIB_CONDS_UTILS_H */