tests: add framework to run code in comp cls / comp / msg iter context
authorSimon Marchi <simon.marchi@efficios.com>
Tue, 23 May 2023 18:19:42 +0000 (14:19 -0400)
committerSimon Marchi <simon.marchi@efficios.com>
Wed, 31 May 2023 19:47:48 +0000 (15:47 -0400)
Add a little framework to make it easier to write tests that need a
bt_self_component_class, bt_self_component or bt_self_message_iterator.
This is inspired from what we have already in
tests/lib/conds/utils.{hpp,cpp}, but decoupled from the
pre/post-condition assertion tests.  A subsequent commit will change
this test to use the new framework.

The framework exposes the run_in function, which accepts three callbacks
that are executed at three different points in the graph's lifecycle,
providing access to all three contexts.  Each callback may be nullptr.

For convenience, there are also three functions to run code in each
individual context:

 - runInCompClsQuery
 - runInCompClsInitFunc
 - runInMsgIterClsInitFunc

If needed, some additional hook points can be added later, to access
other points of the graph's lifecycle.

The run_in function makes an end-to-end run:

 - creates a graph
 - creates a source component class
 - makes a query on that component class
 - adds a source component
 - adds a dummy sink component, connects the ports of the two components
 - runs the graph

Even for a test that only needs to run code in component class context,
for instance, we still run the whole enchilada.  This is a bit
inefficient, but given that this is just for testing, we don't really
care, as it still runs quick.

Change-Id: Ie532b316dc330758b60fd5f6fe9499f0555f8a8a
Signed-off-by: Simon Marchi <simon.marchi@efficios.com>
Reviewed-on: https://review.lttng.org/c/babeltrace/+/10060
Reviewed-by: Philippe Proulx <eeppeliteloop@gmail.com>
Tested-by: jenkins <jenkins@lttng.org>
configure.ac
tests/lib/Makefile.am
tests/lib/utils/Makefile.am [new file with mode: 0644]
tests/lib/utils/run-in.cpp [new file with mode: 0644]
tests/lib/utils/run-in.hpp [new file with mode: 0644]

index 59c0bac16741a4776a446cf7fcf8d156199547ab..364ee76205597ea099a069307ca873ea0567ba82 100644 (file)
@@ -862,6 +862,7 @@ AC_CONFIG_FILES([
   tests/lib/Makefile
   tests/lib/test-plugin-plugins/Makefile
   tests/lib/conds/Makefile
+  tests/lib/utils/Makefile
   tests/Makefile
   tests/param-validation/Makefile
   tests/plugins/Makefile
index c1b68d7ffeb2c978ee3496b0fce678b20da9a87a..cc91bb2bd2a633662b7bd1ee14a44fee327908d6 100644 (file)
@@ -1,6 +1,6 @@
 # SPDX-License-Identifier: MIT
 
-SUBDIRS =
+SUBDIRS = utils
 
 AM_CPPFLAGS += -I$(top_srcdir)/tests/utils
 
diff --git a/tests/lib/utils/Makefile.am b/tests/lib/utils/Makefile.am
new file mode 100644 (file)
index 0000000..21d9017
--- /dev/null
@@ -0,0 +1,2 @@
+noinst_LTLIBRARIES = liblib-utils.la
+liblib_utils_la_SOURCES = run-in.cpp run-in.hpp
diff --git a/tests/lib/utils/run-in.cpp b/tests/lib/utils/run-in.cpp
new file mode 100644 (file)
index 0000000..3a3a0a2
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ * Copyright (C) 2020-2023 EfficiOS, inc.
+ */
+
+#include <utility>
+
+#include "run-in.hpp"
+#include "common/assert.h"
+
+struct RunInData final
+{
+    RunInCompClsQueryFunc compClsCtxFunc;
+    RunInCompClsInitFunc compCtxFunc;
+    RunInMsgIterClsInitFunc msgIterCtxFunc;
+};
+
+static const RunInData& runInDataFromMethodData(void * const methodData)
+{
+    return *static_cast<const RunInData *>(methodData);
+}
+
+static bt_component_class_initialize_method_status
+compClsInit(bt_self_component_source * const selfComp, bt_self_component_source_configuration *,
+            const bt_value *, void * const initMethodData)
+{
+    const auto status =
+        bt_self_component_source_add_output_port(selfComp, "out", initMethodData, nullptr);
+
+    BT_ASSERT(status == BT_SELF_COMPONENT_ADD_PORT_STATUS_OK);
+
+    auto& data = runInDataFromMethodData(initMethodData);
+
+    if (data.compCtxFunc) {
+        data.compCtxFunc(bt_self_component_source_as_self_component(selfComp));
+    }
+
+    return BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_OK;
+}
+
+static bt_component_class_query_method_status
+compClsQuery(bt_self_component_class_source * const selfCompCls, bt_private_query_executor *,
+             const char *, const bt_value *, void * const methodData,
+             const bt_value ** const result)
+{
+    auto& data = runInDataFromMethodData(methodData);
+
+    if (data.compClsCtxFunc) {
+        data.compClsCtxFunc(bt_self_component_class_source_as_self_component_class(selfCompCls));
+    }
+
+    *result = bt_value_null;
+    return BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_OK;
+}
+
+static bt_message_iterator_class_initialize_method_status
+msgIterClsInit(bt_self_message_iterator * const selfMsgIter,
+               bt_self_message_iterator_configuration *, bt_self_component_port_output * const port)
+{
+    auto& data = runInDataFromMethodData(bt_self_component_port_get_data(
+        bt_self_component_port_output_as_self_component_port(port)));
+
+    if (data.msgIterCtxFunc) {
+        data.msgIterCtxFunc(selfMsgIter);
+    }
+
+    return BT_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_STATUS_OK;
+}
+
+static bt_message_iterator_class_next_method_status
+msgIterClsNext(bt_self_message_iterator *, bt_message_array_const, uint64_t, uint64_t *)
+{
+    return BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_END;
+}
+
+void runIn(RunInCompClsQueryFunc compClsCtxFunc, RunInCompClsInitFunc compCtxFunc,
+           RunInMsgIterClsInitFunc msgIterCtxFunc)
+{
+    RunInData data {std::move(compClsCtxFunc), std::move(compCtxFunc), std::move(msgIterCtxFunc)};
+
+    /* Create and configure custom source component class */
+    const auto msgIterCls = bt_message_iterator_class_create(msgIterClsNext);
+
+    BT_ASSERT(msgIterCls);
+
+    {
+        const auto status =
+            bt_message_iterator_class_set_initialize_method(msgIterCls, msgIterClsInit);
+
+        BT_ASSERT(status == BT_MESSAGE_ITERATOR_CLASS_SET_METHOD_STATUS_OK);
+    }
+
+    const auto srcCompCls = bt_component_class_source_create("yo", msgIterCls);
+
+    BT_ASSERT(srcCompCls);
+
+    {
+        const auto status =
+            bt_component_class_source_set_initialize_method(srcCompCls, compClsInit);
+
+        BT_ASSERT(status == BT_COMPONENT_CLASS_SET_METHOD_STATUS_OK);
+    }
+
+    {
+        const auto status = bt_component_class_source_set_query_method(srcCompCls, compClsQuery);
+
+        BT_ASSERT(status == BT_COMPONENT_CLASS_SET_METHOD_STATUS_OK);
+    }
+
+    /* Execute a query (executes `compClsCtxFunc`) */
+    {
+        const auto queryExec = bt_query_executor_create_with_method_data(
+            bt_component_class_source_as_component_class(srcCompCls), "", nullptr, &data);
+
+        BT_ASSERT(queryExec);
+
+        const bt_value *queryRes;
+        const auto status = bt_query_executor_query(queryExec, &queryRes);
+
+        BT_ASSERT(status == BT_QUERY_EXECUTOR_QUERY_STATUS_OK);
+
+        bt_value_put_ref(queryRes);
+        bt_query_executor_put_ref(queryExec);
+    }
+
+    /* Create graph */
+    const auto graph = bt_graph_create(0);
+
+    BT_ASSERT(graph);
+
+    /* Add custom source component (executes `compCtxFunc`) */
+    const bt_component_source *srcComp;
+
+    {
+        const auto status = bt_graph_add_source_component_with_initialize_method_data(
+            graph, srcCompCls, "whatever", NULL, &data, BT_LOGGING_LEVEL_NONE, &srcComp);
+
+        BT_ASSERT(status == BT_GRAPH_ADD_COMPONENT_STATUS_OK);
+    }
+
+    /* Find `sink.utils.dummy` component class */
+    const bt_plugin *utilsPlugin = nullptr;
+
+    {
+        const auto status =
+            bt_plugin_find("utils", BT_TRUE, BT_TRUE, BT_TRUE, BT_TRUE, BT_TRUE, &utilsPlugin);
+
+        BT_ASSERT(status == BT_PLUGIN_FIND_STATUS_OK);
+    }
+
+    /* Add `sink.utils.dummy` component */
+    const bt_component_sink *sinkComp;
+
+    {
+        const auto dummyCompCls =
+            bt_plugin_borrow_sink_component_class_by_name_const(utilsPlugin, "dummy");
+
+        BT_ASSERT(dummyCompCls);
+
+        const auto status = bt_graph_add_sink_component(graph, dummyCompCls, "the-sink", nullptr,
+                                                        BT_LOGGING_LEVEL_NONE, &sinkComp);
+
+        BT_ASSERT(status == BT_GRAPH_ADD_COMPONENT_STATUS_OK);
+    }
+
+    /* Connect ports */
+    {
+        const auto outPort = bt_component_source_borrow_output_port_by_name_const(srcComp, "out");
+
+        BT_ASSERT(outPort);
+
+        const auto inPort = bt_component_sink_borrow_input_port_by_name_const(sinkComp, "in");
+
+        BT_ASSERT(inPort);
+
+        const auto status = bt_graph_connect_ports(graph, outPort, inPort, nullptr);
+
+        BT_ASSERT(status == BT_GRAPH_CONNECT_PORTS_STATUS_OK);
+    }
+
+    /* Run graph (executes `msgIterCtxFunc`) */
+    const auto status = bt_graph_run(graph);
+
+    BT_ASSERT(status == BT_GRAPH_RUN_STATUS_OK);
+
+    /* Discard plugin and graph */
+    bt_plugin_put_ref(utilsPlugin);
+    bt_graph_put_ref(graph);
+    bt_component_class_source_put_ref(srcCompCls);
+    bt_message_iterator_class_put_ref(msgIterCls);
+}
+
+void runInCompClsQuery(RunInCompClsQueryFunc func)
+{
+    runIn(std::move(func), nullptr, nullptr);
+}
+
+void runInCompClsInit(RunInCompClsInitFunc func)
+{
+    runIn(nullptr, std::move(func), nullptr);
+}
+
+void runInMsgIterClsInit(RunInMsgIterClsInitFunc func)
+{
+    runIn(nullptr, nullptr, std::move(func));
+}
diff --git a/tests/lib/utils/run-in.hpp b/tests/lib/utils/run-in.hpp
new file mode 100644 (file)
index 0000000..2220b97
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ * Copyright (C) 2020-2023 EfficiOS, inc.
+ */
+
+#ifndef TESTS_LIB_UTILS_H
+#define TESTS_LIB_UTILS_H
+
+#include <babeltrace2/babeltrace.h>
+#include <functional>
+
+using RunInCompClsQueryFunc = std::function<void(bt_self_component_class *)>;
+using RunInCompClsInitFunc = std::function<void(bt_self_component *)>;
+using RunInMsgIterClsInitFunc = std::function<void(bt_self_message_iterator *)>;
+
+/*
+ * Runs:
+ *
+ * • `compClsCtxFunc` in the context of a component class method,
+ *   if not `nullptr`.
+ *
+ * • `compCtxFunc` in the context of a component method, if not
+ *   `nullptr`.
+ *
+ * • `msgIterCtxFunc` in the context of a message iterator method, if
+ *   not `nullptr`.
+ */
+void runIn(RunInCompClsQueryFunc compClsCtxFunc, RunInCompClsInitFunc compCtxFunc,
+           RunInMsgIterClsInitFunc msgIterCtxFunc);
+
+/*
+ * Runs `func` in the context of a component class method.
+ */
+void runInCompClsQuery(RunInCompClsQueryFunc func);
+
+/*
+ * Runs `func` in the context of a component method.
+ */
+void runInCompClsInit(RunInCompClsInitFunc func);
+
+/*
+ * Runs `func` in the context of a message iterator method.
+ */
+void runInMsgIterClsInit(RunInMsgIterClsInitFunc func);
+
+#endif /* TESTS_LIB_UTILS_H */
This page took 0.028682 seconds and 4 git commands to generate.