aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYordan Karadzhov (VMware) <y.karadz@gmail.com>2021-02-11 12:31:47 +0200
committerYordan Karadzhov (VMware) <y.karadz@gmail.com>2021-02-16 10:25:14 +0200
commit200432d7d7c165b0a4185ac5204b1f0ef0b6c908 (patch)
tree7419edaac3057c6514ce931e1eabda01a881d7a2
parent0da9688e46d163423a3205602517c77e77d5fc48 (diff)
downloadkernel-shark-200432d7d7c165b0a4185ac5204b1f0ef0b6c908.tar.gz
kernel-shark: Add plugin tests
We add a number of dummy plugins and we test the plugin-related part of the C API. We also add few simple test cases of the functionalities provided in KSUtils. Link: https://lore.kernel.org/linux-trace-devel/20210211103205.418588-10-y.karadz@gmail.com Signed-off-by: Yordan Karadzhov (VMware) <y.karadz@gmail.com>
-rw-r--r--CMakeLists.txt11
-rwxr-xr-xbuild/cmake_clean.sh2
-rw-r--r--build/deff.h.cmake3
-rw-r--r--src/CMakeLists.txt4
-rw-r--r--tests/CMakeLists.txt34
-rw-r--r--tests/libkshark-gui-tests.cpp227
-rw-r--r--tests/libkshark-tests.cpp309
-rw-r--r--tests/test-input.c134
-rw-r--r--tests/test-input_ctrl.c140
-rw-r--r--tests/test-plugin_dpi.c26
-rw-r--r--tests/test-plugin_dpi_ctrl.c32
-rw-r--r--tests/test-plugin_dpi_err.c26
12 files changed, 934 insertions, 14 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 26fb7ae2..b9b947eb 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -144,10 +144,13 @@ if (_DOXYGEN_DOC AND DOXYGEN_FOUND)
endif ()
-configure_file( ${KS_DIR}/build/ks.desktop.cmake
- ${KS_DIR}/${KS_APP_NAME}.desktop)
+configure_file(${KS_DIR}/build/deff.h.cmake
+ ${KS_DIR}/src/KsCmakeDef.hpp)
-configure_file( ${KS_DIR}/build/org.freedesktop.kshark-record.policy.cmake
- ${KS_DIR}/org.freedesktop.kshark-record.policy)
+configure_file(${KS_DIR}/build/ks.desktop.cmake
+ ${KS_DIR}/${KS_APP_NAME}.desktop)
+
+configure_file(${KS_DIR}/build/org.freedesktop.kshark-record.policy.cmake
+ ${KS_DIR}/org.freedesktop.kshark-record.policy)
message("")
diff --git a/build/cmake_clean.sh b/build/cmake_clean.sh
index b5340147..2ca1136a 100755
--- a/build/cmake_clean.sh
+++ b/build/cmake_clean.sh
@@ -3,7 +3,7 @@ rm CMakeCache.txt
rm cmake_install.cmake
rm Makefile
rm CTestTestfile.cmake
-rm DartConfiguration.tcl
+rm -f DartConfiguration.tcl
rm -rf CMakeFiles/
rm -rf src/
rm -rf examples/
diff --git a/build/deff.h.cmake b/build/deff.h.cmake
index 5584574f..423a2fd2 100644
--- a/build/deff.h.cmake
+++ b/build/deff.h.cmake
@@ -29,6 +29,9 @@
/** Qt - old version detected. */
#cmakedefine QT_VERSION_LESS_5_11
+/** Location of the KernelShark tests. */
+#cmakedefine KS_TEST_DIR "@KS_TEST_DIR@"
+
/** Semicolon-separated list of plugin names. */
#define KS_BUILTIN_PLUGINS "@PLUGINS@"
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 21d5b855..b308403a 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -137,8 +137,6 @@ if (Qt5Widgets_FOUND AND Qt5Network_FOUND)
endif (Qt5Widgets_FOUND AND Qt5Network_FOUND)
add_subdirectory(plugins)
+set(PLUGINS ${PLUGINS} PARENT_SCOPE)
find_program(DO_AS_ROOT pkexec)
-
-configure_file( ${KS_DIR}/build/deff.h.cmake
- ${KS_DIR}/src/KsCmakeDef.hpp)
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 08474149..28f711bf 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -1,18 +1,50 @@
message("\n tests ...")
set(EXECUTABLE_OUTPUT_PATH ${KS_TEST_DIR})
+set(LIBRARY_OUTPUT_PATH ${KS_TEST_DIR})
add_executable(kshark-tests libkshark-tests.cpp)
target_include_directories(kshark-tests PRIVATE ${Boost_INCLUDE_DIRS})
target_compile_definitions(kshark-tests PRIVATE "BOOST_TEST_DYN_LINK=1")
-target_link_libraries(kshark-tests kshark-gui
+target_link_libraries(kshark-tests kshark
${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})
add_test(NAME "get_test_data"
COMMAND ${KS_TEST_DIR}/get_test_data.sh
WORKING_DIRECTORY ${KS_TEST_DIR})
+add_library(dummy_dpi SHARED test-plugin_dpi.c)
+set_target_properties(dummy_dpi PROPERTIES PREFIX "plugin-")
+target_link_libraries(dummy_dpi kshark)
+
+add_library(dummy_dpi_ctrl SHARED test-plugin_dpi_ctrl.c)
+set_target_properties(dummy_dpi_ctrl PROPERTIES PREFIX "plugin-")
+target_link_libraries(dummy_dpi_ctrl kshark)
+
+add_library(dummy_dpi_err SHARED test-plugin_dpi_err.c)
+set_target_properties(dummy_dpi_err PROPERTIES PREFIX "plugin-")
+target_link_libraries(dummy_dpi_err kshark)
+
+add_library(dummy_input SHARED test-input.c)
+set_target_properties(dummy_input PROPERTIES PREFIX "input-")
+target_link_libraries(dummy_input kshark)
+
+add_library(dummy_input_ctrl SHARED test-input_ctrl.c)
+set_target_properties(dummy_input_ctrl PROPERTIES PREFIX "input-")
+target_link_libraries(dummy_input_ctrl kshark)
+
message(STATUS "libkshark-tests")
add_test(NAME "libkshark_tests"
COMMAND ${KS_TEST_DIR}/kshark-tests --log_format=HRF
WORKING_DIRECTORY ${KS_TEST_DIR})
+
+add_executable(kshark-gui-tests libkshark-gui-tests.cpp)
+target_include_directories(kshark-gui-tests PRIVATE ${Boost_INCLUDE_DIRS})
+target_compile_definitions(kshark-gui-tests PRIVATE "BOOST_TEST_DYN_LINK=1")
+target_link_libraries(kshark-gui-tests kshark-gui
+ ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})
+
+message(STATUS "libkshark-gui_tests")
+add_test(NAME "libkshark-gui_tests"
+ COMMAND ${KS_TEST_DIR}/kshark-gui-tests --log_format=HRF
+ WORKING_DIRECTORY ${KS_TEST_DIR})
diff --git a/tests/libkshark-gui-tests.cpp b/tests/libkshark-gui-tests.cpp
new file mode 100644
index 00000000..de6eb302
--- /dev/null
+++ b/tests/libkshark-gui-tests.cpp
@@ -0,0 +1,227 @@
+// SPDX-License-Identifier: LGPL-2.1
+
+/*
+ * Copyright (C) 2020 VMware Inc, Yordan Karadzhov (VMware) <y.karadz@gmail.com>
+ */
+
+// Boost
+#define BOOST_TEST_MODULE KernelSharkTests
+#include <boost/test/unit_test.hpp>
+
+// KernelShark
+#include "libkshark.h"
+#include "libkshark-plugin.h"
+#include "KsUtils.hpp"
+
+using namespace KsUtils;
+
+#define N_RECORDS_TEST1 1530
+
+BOOST_AUTO_TEST_CASE(KsUtils_datatest)
+{
+ kshark_context *kshark_ctx{nullptr};
+ kshark_entry **data{nullptr};
+ std::string file(KS_TEST_DIR);
+ ssize_t n_rows;
+ int sd, ss_id;
+
+ BOOST_REQUIRE(kshark_instance(&kshark_ctx));
+ file += "/trace_test1.dat";
+ sd = kshark_open(kshark_ctx, file.c_str());
+ BOOST_CHECK_EQUAL(sd, 0);
+
+ n_rows = kshark_load_entries(kshark_ctx, sd, &data);
+ BOOST_CHECK_EQUAL(n_rows, N_RECORDS_TEST1);
+
+ auto cpus = getCPUList(sd);
+ BOOST_CHECK_EQUAL(cpus.size(), 8);
+ for (int i = 0; i < cpus.size(); ++i)
+ BOOST_CHECK_EQUAL(cpus[i], i);
+
+ auto pids = getPidList(sd);
+ BOOST_CHECK_EQUAL(pids.size(), 46);
+ BOOST_CHECK_EQUAL(pids[0], 0);
+ for (int i = 1; i < pids.size(); ++i)
+ BOOST_CHECK(pids[i] > pids[i - 1]);
+
+ auto evts = getEventIdList(sd);
+ BOOST_CHECK_EQUAL(evts.size(), 40);
+ BOOST_CHECK_EQUAL(evts[34], 323);
+
+ ss_id = getEventId(sd, "sched/sched_switch");
+ BOOST_CHECK_EQUAL(ss_id, 323);
+
+ QString name = getEventName(sd, 323);
+ BOOST_CHECK(name == QString("sched/sched_switch"));
+ name = getEventName(sd, 999);
+ BOOST_CHECK(name == QString("Unknown"));
+
+ auto fields = getEventFieldsList(sd, ss_id);
+ BOOST_CHECK_EQUAL(fields.size(), 11);
+ BOOST_CHECK(fields[10] == QString("next_prio"));
+
+ BOOST_CHECK_EQUAL(getEventFieldType(sd, ss_id, "next_prio"),
+ KS_INTEGER_FIELD);
+
+ BOOST_CHECK_EQUAL(getEventFieldType(sd, ss_id, "next_comm"),
+ KS_INVALID_FIELD);
+
+ for (ssize_t r = 0; r < n_rows; ++r)
+ free(data[r]);
+ free(data);
+
+ kshark_close(kshark_ctx, sd);
+ kshark_free(kshark_ctx);
+}
+
+BOOST_AUTO_TEST_CASE(KsUtils_setFilterSync)
+{
+ struct kshark_context *kshark_ctx{nullptr};
+
+ BOOST_REQUIRE(kshark_instance(&kshark_ctx));
+ kshark_ctx->filter_mask = KS_TEXT_VIEW_FILTER_MASK |
+ KS_GRAPH_VIEW_FILTER_MASK |
+ KS_EVENT_VIEW_FILTER_MASK;
+
+ BOOST_CHECK_EQUAL(kshark_ctx->filter_mask, 0x7);
+
+ listFilterSync(false);
+ BOOST_CHECK_EQUAL(kshark_ctx->filter_mask & KS_TEXT_VIEW_FILTER_MASK, 0);
+ BOOST_CHECK_EQUAL(kshark_ctx->filter_mask & KS_GRAPH_VIEW_FILTER_MASK,
+ KS_GRAPH_VIEW_FILTER_MASK);
+ BOOST_CHECK_EQUAL(kshark_ctx->filter_mask & KS_EVENT_VIEW_FILTER_MASK,
+ KS_EVENT_VIEW_FILTER_MASK);
+ listFilterSync(true);
+ BOOST_CHECK_EQUAL(kshark_ctx->filter_mask, 0x7);
+
+ graphFilterSync(false);
+ BOOST_CHECK_EQUAL(kshark_ctx->filter_mask & KS_TEXT_VIEW_FILTER_MASK,
+ KS_TEXT_VIEW_FILTER_MASK);
+ BOOST_CHECK_EQUAL(kshark_ctx->filter_mask & KS_GRAPH_VIEW_FILTER_MASK, 0);
+ BOOST_CHECK_EQUAL(kshark_ctx->filter_mask & KS_EVENT_VIEW_FILTER_MASK, 0);
+ graphFilterSync(true);
+ BOOST_CHECK_EQUAL(kshark_ctx->filter_mask, 0x7);
+
+ kshark_free(kshark_ctx);
+}
+
+BOOST_AUTO_TEST_CASE(KsUtils_parseIds)
+{
+ QVector<int> ids_test = parseIdList("1,33,4-6,3,55-57");
+ QVector<int> ids = {1, 33, 4, 5, 6, 3, 55, 56, 57};
+ BOOST_CHECK(ids == ids_test);
+}
+
+#define N_RECORDS_TEST2 73945
+BOOST_AUTO_TEST_CASE(KsUtils_KsDataStore)
+{
+ int64_t ts_last(0);
+ KsDataStore data;
+ int sd;
+
+ BOOST_CHECK_EQUAL(data.size(), 0);
+ BOOST_CHECK_EQUAL(data.rows(), nullptr);
+
+ sd = data.loadDataFile(QString(KS_TEST_DIR) + "/trace_test1.dat", {});
+ BOOST_CHECK_EQUAL(sd, 0);
+ BOOST_CHECK_EQUAL(data.size(), N_RECORDS_TEST1);
+ BOOST_CHECK(data.rows() != nullptr);
+
+ sd = data.appendDataFile(QString(KS_TEST_DIR) + "/trace_test2.dat", {});
+ BOOST_CHECK_EQUAL(sd, 1);
+ BOOST_CHECK_EQUAL(data.size(), N_RECORDS_TEST1 + N_RECORDS_TEST2);
+
+ kshark_entry **rows = data.rows();
+ for (ssize_t i = 0; i < data.size(); ++i) {
+ BOOST_CHECK(rows[i]->ts >= ts_last);
+ ts_last = rows[i]->ts;
+ }
+
+ data.clear();
+ BOOST_CHECK_EQUAL(data.size(), 0);
+ BOOST_CHECK_EQUAL(data.rows(), nullptr);
+}
+
+BOOST_AUTO_TEST_CASE(KsUtils_getPluginList)
+{
+ QStringList plugins{"sched_events"};
+
+ BOOST_CHECK(getPluginList() == plugins);
+}
+
+#define PLUGIN_1_LIB "/plugin-dummy_dpi.so"
+#define PLUGIN_2_LIB "/plugin-dummy_dpi_ctrl.so"
+#define INPUT_A_LIB "/input-dummy_input.so"
+
+QString path(KS_TEST_DIR);
+
+BOOST_AUTO_TEST_CASE(KsUtils_KsPluginManager)
+{
+ struct kshark_context *kshark_ctx = NULL;
+ int sd, argc{0};
+ QCoreApplication a(argc, nullptr);
+
+ KsPluginManager pm;
+ pm.registerPlugins(path + INPUT_A_LIB);
+
+ kshark_instance(&kshark_ctx);
+ BOOST_CHECK_EQUAL(kshark_ctx->n_inputs, 1);
+ BOOST_CHECK(kshark_ctx->inputs != nullptr);
+
+ sd = kshark_add_stream(kshark_ctx);
+ BOOST_CHECK_EQUAL(sd, 0);
+ kshark_ctx->stream[sd]->interface =
+ malloc(1);
+
+ sd = kshark_add_stream(kshark_ctx);
+ BOOST_CHECK_EQUAL(sd, 1);
+ kshark_ctx->stream[sd]->interface = malloc(1);
+
+ pm.registerPluginToStream("sched_events",
+ getStreamIdList(kshark_ctx));
+
+ QStringList list = pm.getStreamPluginList(sd);
+ BOOST_CHECK_EQUAL(list.count(), 1);
+ BOOST_CHECK(list[0] == "sched_events");
+
+ QString testPlugins = path + PLUGIN_1_LIB + ",";
+ testPlugins += path + PLUGIN_2_LIB;
+ pm.registerPlugins(testPlugins);
+ auto listTest = pm.getUserPlugins();
+ BOOST_CHECK_EQUAL(listTest.count(), 3);
+ list = pm.getStreamPluginList(sd);
+
+ for (auto const &p: listTest)
+ pm.registerPluginToStream(p->name, {sd});
+
+ list = pm.getStreamPluginList(sd);
+ BOOST_CHECK_EQUAL(list.count(), 3);
+
+ BOOST_CHECK(list == QStringList({"dummy_dpi_ctrl",
+ "dummy_dpi",
+ "sched_events"}));
+
+ auto active = pm.getActivePlugins(sd);
+ BOOST_CHECK(pm.getActivePlugins(sd) == QVector<int>({1, 1, 1}));
+
+ auto enabled = pm.getPluginsByStatus(sd, KSHARK_PLUGIN_ENABLED);
+ BOOST_CHECK(enabled == QVector<int>({0, 1, 2}));
+ auto loaded = pm.getPluginsByStatus(sd, KSHARK_PLUGIN_LOADED);
+ BOOST_CHECK(loaded == QVector<int>({0, 1}));
+ auto failed = pm.getPluginsByStatus(sd, KSHARK_PLUGIN_FAILED);
+ BOOST_CHECK(failed == QVector<int>({2}));
+
+ active[1] = 0;
+ pm.updatePlugins(sd, active);
+ BOOST_CHECK(active == pm.getActivePlugins(sd));
+
+ enabled = pm.getPluginsByStatus(sd, KSHARK_PLUGIN_ENABLED);
+ BOOST_CHECK(enabled == QVector<int>({0, 2}));
+ loaded = pm.getPluginsByStatus(sd, KSHARK_PLUGIN_LOADED);
+ BOOST_CHECK(loaded == QVector<int>({0}));
+ failed = pm.getPluginsByStatus(sd, KSHARK_PLUGIN_FAILED);
+ BOOST_CHECK(failed == QVector<int>({2}));
+
+ kshark_free(kshark_ctx);
+ a.exit();
+}
diff --git a/tests/libkshark-tests.cpp b/tests/libkshark-tests.cpp
index eb5cb1fb..a22c1e58 100644
--- a/tests/libkshark-tests.cpp
+++ b/tests/libkshark-tests.cpp
@@ -11,6 +11,7 @@
// KernelShark
#include "libkshark.h"
#include "libkshark-plugin.h"
+#include "KsCmakeDef.hpp"
#define N_TEST_STREAMS 1000
@@ -19,7 +20,7 @@ BOOST_AUTO_TEST_CASE(add_remove_streams)
struct kshark_context *kshark_ctx = NULL;
int sd, free = 0, i;
- kshark_instance(&kshark_ctx);
+ BOOST_REQUIRE(kshark_instance(&kshark_ctx));
for (i = 0; i < N_TEST_STREAMS; ++i) {
sd = kshark_add_stream(kshark_ctx);
@@ -45,10 +46,46 @@ BOOST_AUTO_TEST_CASE(add_remove_streams)
BOOST_CHECK_EQUAL(kshark_ctx->stream_info.array_size, INT16_MAX + 1);
BOOST_CHECK_EQUAL(sd, -ENODEV);
- kshark_close_all(kshark_ctx);
kshark_free(kshark_ctx);
}
+BOOST_AUTO_TEST_CASE(get_stream)
+{
+ kshark_context *kshark_ctx(nullptr);
+ kshark_data_stream *stream;
+ int sd;
+
+ BOOST_REQUIRE(kshark_instance(&kshark_ctx));
+ sd = kshark_add_stream(kshark_ctx);
+ stream = kshark_get_data_stream(kshark_ctx, sd);
+ BOOST_CHECK_EQUAL(stream, nullptr);
+
+ kshark_ctx->stream[sd]->interface = malloc(1);
+ stream = kshark_get_data_stream(kshark_ctx, sd);
+ BOOST_CHECK(stream != nullptr);
+
+ kshark_free(kshark_ctx);
+}
+
+BOOST_AUTO_TEST_CASE(close_all)
+{
+ struct kshark_context *kshark_ctx(nullptr);
+ int sd, i;
+
+ BOOST_REQUIRE(kshark_instance(&kshark_ctx));
+ for (i = 0; i < N_TEST_STREAMS; ++i) {
+ sd = kshark_add_stream(kshark_ctx);
+ BOOST_CHECK_EQUAL(sd, i);
+ }
+
+ kshark_close_all(kshark_ctx);
+ BOOST_CHECK_EQUAL(kshark_ctx->n_streams, 0);
+ BOOST_CHECK_EQUAL(kshark_ctx->stream_info.next_free_stream_id, 0);
+ BOOST_CHECK_EQUAL(kshark_ctx->stream_info.max_stream_id, -1);
+ for (i = 0; i < kshark_ctx->stream_info.array_size; ++i)
+ BOOST_CHECK_EQUAL(kshark_ctx->stream[i], nullptr);
+}
+
#define ARRAY_DEFAULT_SIZE 1000
BOOST_AUTO_TEST_CASE(doule_size_macro)
{
@@ -90,7 +127,7 @@ BOOST_AUTO_TEST_CASE(fill_data_container)
kshark_data_container_sort(data);
BOOST_CHECK_EQUAL(data->capacity, N_VALUES);
for (i = 0; i < N_VALUES; ++i) {
- BOOST_REQUIRE(data->data[i]->entry->ts >= ts_last);
+ BOOST_CHECK(data->data[i]->entry->ts >= ts_last);
BOOST_CHECK_EQUAL(data->data[i]->entry->ts,
10 - data->data[i]->field);
@@ -100,8 +137,8 @@ BOOST_AUTO_TEST_CASE(fill_data_container)
i = kshark_find_entry_field_by_time(MAX_TS / 2, data->data,
0, N_VALUES - 1);
- BOOST_REQUIRE(data->data[i - 1]->entry->ts < MAX_TS / 2);
- BOOST_REQUIRE(data->data[i]->entry->ts >= MAX_TS / 2);
+ BOOST_CHECK(data->data[i - 1]->entry->ts < MAX_TS / 2);
+ BOOST_CHECK(data->data[i]->entry->ts >= MAX_TS / 2);
kshark_free_data_container(data);
}
@@ -136,3 +173,265 @@ BOOST_AUTO_TEST_CASE(init_close_plugin)
__close(-1);
}
+
+#define PLUGIN_1_LIB "/plugin-dummy_dpi.so"
+#define PLUGIN_1_NAME "dummy_dpi"
+
+#define PLUGIN_2_LIB "/plugin-dummy_dpi_ctrl.so"
+#define PLUGIN_2_NAME "dummy_dpi_ctrl"
+
+#define INPUT_A_LIB "/input-dummy_input.so"
+#define INPUT_A_NAME "dummy_input"
+
+#define INPUT_B_LIB "/input-dummy_input_ctrl.so"
+#define INPUT_B_NAME "dummy_input_ctrl"
+
+std::string path(KS_TEST_DIR);
+
+BOOST_AUTO_TEST_CASE(register_plugin)
+{
+ kshark_plugin_list *p1, *p2, *i1, *i2, *x1, *x2;
+ kshark_generic_stream_interface *interface;
+ kshark_context *kshark_ctx(nullptr);
+ kshark_data_stream *stream;
+ std::string plugin;
+ int sd;
+
+ BOOST_REQUIRE(kshark_instance(&kshark_ctx));
+ BOOST_REQUIRE(kshark_ctx->plugins == nullptr);
+ BOOST_REQUIRE(kshark_ctx->inputs == nullptr);
+ BOOST_CHECK_EQUAL(kshark_ctx->n_plugins, 0);
+
+ plugin = path + PLUGIN_1_LIB;
+ p1 = kshark_register_plugin(kshark_ctx, PLUGIN_1_NAME, plugin.c_str());
+ BOOST_CHECK_EQUAL(kshark_ctx->n_plugins, 1);
+ BOOST_CHECK(kshark_ctx->plugins != nullptr);
+ BOOST_CHECK_EQUAL(kshark_ctx->plugins->next, nullptr);
+ BOOST_CHECK_EQUAL(kshark_ctx->plugins, p1);
+ BOOST_CHECK(p1 != nullptr);
+ BOOST_CHECK(p1->process_interface != nullptr);
+ BOOST_CHECK(p1->handle != nullptr);
+ BOOST_CHECK_EQUAL(strcmp(p1->file, plugin.c_str()), 0);
+ BOOST_CHECK_EQUAL(strcmp(p1->name, PLUGIN_1_NAME), 0);
+
+ BOOST_CHECK_EQUAL(p1->ctrl_interface, nullptr);
+ BOOST_CHECK_EQUAL(p1->readout_interface, nullptr);
+
+ plugin = path + PLUGIN_2_LIB;
+ p2 = kshark_register_plugin(kshark_ctx, PLUGIN_2_NAME, plugin.c_str());
+ BOOST_CHECK_EQUAL(kshark_ctx->n_plugins, 2);
+ BOOST_CHECK_EQUAL(kshark_ctx->plugins, p2);
+ BOOST_CHECK_EQUAL(kshark_ctx->plugins->next, p1);
+ BOOST_CHECK(p2 != nullptr);
+ BOOST_CHECK(p2->process_interface != nullptr);
+ BOOST_CHECK(p2->handle != nullptr);
+ BOOST_CHECK_EQUAL(strcmp(p2->file, plugin.c_str()), 0);
+ BOOST_CHECK_EQUAL(strcmp(p2->name, PLUGIN_2_NAME), 0);
+ BOOST_CHECK(p2->ctrl_interface != nullptr);
+
+ BOOST_CHECK_EQUAL(p2->readout_interface, nullptr);
+
+ plugin = path + INPUT_A_LIB;
+ i1 = kshark_register_plugin(kshark_ctx, INPUT_A_NAME, plugin.c_str());
+ BOOST_CHECK(i1 != nullptr);
+ BOOST_CHECK_EQUAL(kshark_ctx->n_plugins, 3);
+ BOOST_CHECK_EQUAL(kshark_ctx->n_inputs, 1);
+ BOOST_CHECK(kshark_ctx->inputs != nullptr);
+ BOOST_CHECK(i1->readout_interface != nullptr);
+ BOOST_CHECK(i1->handle != nullptr);
+ BOOST_CHECK_EQUAL(strcmp(i1->file, plugin.c_str()), 0);
+ BOOST_CHECK_EQUAL(strcmp(i1->name, INPUT_A_NAME), 0);
+
+ BOOST_CHECK_EQUAL(i1->ctrl_interface, nullptr);
+ BOOST_CHECK_EQUAL(i1->process_interface, nullptr);
+
+ plugin = path + INPUT_B_LIB;
+ i2 = kshark_register_plugin(kshark_ctx, INPUT_B_NAME, plugin.c_str());
+ BOOST_CHECK(i2 != nullptr);
+ BOOST_CHECK_EQUAL(kshark_ctx->n_plugins, 4);
+ BOOST_CHECK_EQUAL(kshark_ctx->n_inputs, 2);
+ BOOST_CHECK(i2->readout_interface != nullptr);
+ BOOST_CHECK(i2->handle != nullptr);
+ BOOST_CHECK(strcmp(i2->file, plugin.c_str()) == 0);
+ BOOST_CHECK(strcmp(i2->name, INPUT_B_NAME) == 0);
+ BOOST_CHECK(i2->ctrl_interface != nullptr);
+
+ BOOST_CHECK_EQUAL(i2->process_interface, nullptr);
+
+ x1 = kshark_find_plugin_by_name(kshark_ctx->plugins, PLUGIN_2_NAME);
+ BOOST_CHECK_EQUAL(x1, p2);
+
+ plugin = path + PLUGIN_2_LIB;
+ x2 = kshark_find_plugin(kshark_ctx->plugins, plugin.c_str());
+
+ BOOST_CHECK_EQUAL(x2, p2);
+
+ sd = kshark_add_stream(kshark_ctx);
+ interface =
+ (kshark_generic_stream_interface *) malloc(sizeof(*interface));
+ kshark_ctx->stream[sd]->interface = interface;
+ BOOST_CHECK_EQUAL(sd, 0);
+
+ stream = kshark_get_data_stream(kshark_ctx, sd);
+ BOOST_CHECK(stream != nullptr);
+
+ BOOST_CHECK_EQUAL(stream->plugins, nullptr);
+ kshark_register_plugin_to_stream(stream,
+ p1->process_interface,
+ true);
+ BOOST_CHECK_EQUAL(stream->n_plugins, 1);
+ BOOST_CHECK_EQUAL(stream->plugins->interface, p1->process_interface);
+ BOOST_CHECK_EQUAL(stream->plugins->next, nullptr);
+
+ kshark_register_plugin_to_stream(stream,
+ p2->process_interface,
+ true);
+ BOOST_CHECK_EQUAL(stream->n_plugins, 2);
+ BOOST_CHECK_EQUAL(stream->plugins->interface, p2->process_interface);
+ BOOST_CHECK_EQUAL(stream->plugins->next->interface, p1->process_interface);
+
+ kshark_unregister_plugin_from_stream(stream, p1->process_interface);
+ BOOST_CHECK_EQUAL(stream->n_plugins, 1);
+ BOOST_CHECK_EQUAL(stream->plugins->interface, p2->process_interface);
+ BOOST_CHECK_EQUAL(stream->plugins->next, nullptr);
+
+ kshark_free(kshark_ctx);
+}
+
+#define PLUGIN_ERR_LIB "/plugin-dummy_dpi_err.so"
+#define PLUGIN_ERR_NAME "dummy_dpi_err"
+
+BOOST_AUTO_TEST_CASE(handle_plugin)
+{
+ kshark_dpi_list *dpi1, *dpi2, *dpi_err;
+ kshark_plugin_list *p1, *p2, *p_err;
+ kshark_context *kshark_ctx(nullptr);
+ kshark_data_stream *stream;
+ std::string plugin;
+ int sd, ret;
+
+ BOOST_REQUIRE(kshark_instance(&kshark_ctx));
+ BOOST_CHECK_EQUAL(kshark_ctx->plugins, nullptr);
+ BOOST_CHECK_EQUAL(kshark_ctx->n_plugins, 0);
+
+ plugin = path + PLUGIN_1_LIB;
+ p1 = kshark_register_plugin(kshark_ctx, PLUGIN_1_NAME, plugin.c_str());
+
+ plugin = path + PLUGIN_2_LIB;
+ p2 = kshark_register_plugin(kshark_ctx, PLUGIN_2_NAME, plugin.c_str());
+ BOOST_CHECK(kshark_ctx->plugins != nullptr);
+ BOOST_CHECK_EQUAL(kshark_ctx->n_plugins, 2);
+
+ sd = kshark_add_stream(kshark_ctx);
+ kshark_ctx->stream[sd]->interface = malloc(1);
+ stream = kshark_get_data_stream(kshark_ctx, sd);
+ BOOST_CHECK(stream != nullptr);
+
+ dpi1 = kshark_register_plugin_to_stream(stream,
+ p1->process_interface,
+ true);
+ BOOST_CHECK_EQUAL(dpi1->status, KSHARK_PLUGIN_ENABLED);
+
+ dpi2 = kshark_register_plugin_to_stream(stream,
+ p2->process_interface,
+ false);
+ BOOST_CHECK_EQUAL(dpi2->status, 0);
+
+ ret = kshark_handle_dpi(stream, dpi1, KSHARK_PLUGIN_INIT);
+ BOOST_CHECK_EQUAL(ret, 1);
+ BOOST_CHECK_EQUAL(dpi1->status,
+ KSHARK_PLUGIN_LOADED | KSHARK_PLUGIN_ENABLED);
+
+ ret = kshark_handle_dpi(stream, dpi2, KSHARK_PLUGIN_INIT);
+ BOOST_CHECK_EQUAL(ret, 0);
+ BOOST_CHECK_EQUAL(dpi2->status, 0);
+
+ dpi2->status |= KSHARK_PLUGIN_ENABLED;
+ ret = kshark_handle_dpi(stream, dpi2, KSHARK_PLUGIN_INIT);
+ BOOST_CHECK_EQUAL(ret, 2);
+ BOOST_CHECK_EQUAL(dpi1->status,
+ KSHARK_PLUGIN_LOADED | KSHARK_PLUGIN_ENABLED);
+
+ ret = kshark_handle_all_dpis(stream, KSHARK_PLUGIN_UPDATE);
+ BOOST_CHECK_EQUAL(ret, 0);
+ BOOST_CHECK_EQUAL(dpi1->status,
+ KSHARK_PLUGIN_LOADED | KSHARK_PLUGIN_ENABLED);
+ BOOST_CHECK_EQUAL(dpi2->status,
+ KSHARK_PLUGIN_LOADED | KSHARK_PLUGIN_ENABLED);
+
+ plugin = path + PLUGIN_ERR_LIB;
+ p_err = kshark_register_plugin(kshark_ctx, PLUGIN_ERR_NAME,
+ plugin.c_str());
+ BOOST_CHECK_EQUAL(kshark_ctx->n_plugins, 3);
+ dpi_err = kshark_register_plugin_to_stream(stream,
+ p_err->process_interface,
+ true);
+ BOOST_CHECK_EQUAL(ret, 0);
+ ret = kshark_handle_dpi(stream, dpi_err, KSHARK_PLUGIN_INIT);
+ BOOST_CHECK_EQUAL(dpi_err->status,
+ KSHARK_PLUGIN_FAILED | KSHARK_PLUGIN_ENABLED);
+ BOOST_CHECK_EQUAL(ret, 0);
+ ret = kshark_handle_dpi(stream, dpi_err, KSHARK_PLUGIN_CLOSE);
+ BOOST_CHECK_EQUAL(ret, 0);
+ BOOST_CHECK_EQUAL(dpi_err->status, KSHARK_PLUGIN_ENABLED);
+
+ ret = kshark_handle_all_dpis(stream, KSHARK_PLUGIN_CLOSE);
+ BOOST_CHECK_EQUAL(ret, -3);
+
+ kshark_free(kshark_ctx);
+}
+
+#define FAKE_DATA_FILE_A "test.ta"
+#define FAKE_DATA_A_SIZE 200
+
+#define FAKE_DATA_FILE_B "test.tb"
+#define FAKE_DATA_B_SIZE 100
+
+BOOST_AUTO_TEST_CASE(readout_plugins)
+{
+ kshark_context *kshark_ctx(nullptr);
+ kshark_entry **entries{nullptr};
+ kshark_data_stream *stream;
+ std::string plugin, data;
+ int sd, i, n_entries;
+ int64_t ts_last(0);
+
+ BOOST_REQUIRE(kshark_instance(&kshark_ctx));
+
+ plugin = path + INPUT_A_LIB;
+ kshark_register_plugin(kshark_ctx, INPUT_A_NAME, plugin.c_str());
+ plugin = path + INPUT_B_LIB;
+ kshark_register_plugin(kshark_ctx, INPUT_B_NAME, plugin.c_str());
+
+ data = FAKE_DATA_FILE_A;
+ sd = kshark_open(kshark_ctx, data.c_str());
+ BOOST_CHECK_EQUAL(sd, 0);
+
+ stream = kshark_get_data_stream(kshark_ctx, sd);
+ BOOST_CHECK(stream != nullptr);
+ BOOST_CHECK(stream->interface != nullptr);
+ BOOST_CHECK_EQUAL(strcmp(stream->data_format, "format_a"), 0);
+
+ data = FAKE_DATA_FILE_B;
+ sd = kshark_open(kshark_ctx, data.c_str());
+ BOOST_CHECK_EQUAL(sd, 1);
+
+ stream = kshark_get_data_stream(kshark_ctx, sd);
+ BOOST_CHECK(stream != nullptr);
+ BOOST_CHECK(stream->interface != nullptr);
+ BOOST_CHECK_EQUAL(strcmp(stream->data_format, "format_b"), 0);
+
+ n_entries = kshark_load_all_entries(kshark_ctx, &entries);
+ BOOST_CHECK_EQUAL(n_entries, FAKE_DATA_A_SIZE + FAKE_DATA_B_SIZE);
+
+ for (i = 0; i < n_entries; ++i) {
+ BOOST_CHECK(ts_last <= entries[i]->ts);
+ ts_last = entries[i]->ts;
+ }
+
+ for (i = 0; i < n_entries; ++i)
+ free(entries[i]);
+ free(entries);
+
+ kshark_free(kshark_ctx);
+}
diff --git a/tests/test-input.c b/tests/test-input.c
new file mode 100644
index 00000000..31620b97
--- /dev/null
+++ b/tests/test-input.c
@@ -0,0 +1,134 @@
+
+// C
+#ifndef _GNU_SOURCE
+/** Use GNU C Library. */
+#define _GNU_SOURCE
+#endif // _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+// KernelShark
+#include "libkshark.h"
+#include "libkshark-plugin.h"
+
+static ssize_t load_entries(struct kshark_data_stream *stream,
+ struct kshark_context *kshark_ctx,
+ struct kshark_entry ***data_rows)
+{
+ struct kshark_entry **rows;
+ ssize_t total = 200, i;
+
+ rows = calloc(total, sizeof(struct kshark_entry *));
+ for (i = 0; i < total; ++i) {
+ rows[i] = calloc(1, sizeof(struct kshark_entry));
+ rows[i]->ts = 1000000 + i * 10000;
+ rows[i]->stream_id = stream->stream_id;
+ rows[i]->event_id = i % 5;
+ rows[i]->pid = 10 + i % 2;
+ rows[i]->cpu = i % 2;
+ rows[i]->visible = 0xff;
+ }
+
+ *data_rows = rows;
+ return total;
+}
+
+static char *dump_entry(struct kshark_data_stream *stream,
+ const struct kshark_entry *entry)
+{
+ char *entry_str;
+ int ret;
+
+ ret = asprintf(&entry_str, "e: time=%li evt=%i s_id=%i", entry->ts,
+ entry->event_id,
+ entry->stream_id);
+
+ if (ret <= 0)
+ return NULL;
+
+ return entry_str;
+}
+
+static const char *format_name = "format_a";
+
+const char *KSHARK_INPUT_FORMAT()
+{
+ return format_name;
+}
+
+bool KSHARK_INPUT_CHECK(const char *file, char **format)
+{
+ char *ext = strrchr(file, '.');
+
+ if (ext && strcmp(ext, ".ta") == 0)
+ return true;
+
+ return false;
+}
+
+static const int get_pid(struct kshark_data_stream *stream,
+ const struct kshark_entry *entry)
+{
+ return entry->pid;
+}
+
+static char *get_task(struct kshark_data_stream *stream,
+ const struct kshark_entry *entry)
+{
+ char *entry_str;
+ int ret;
+
+ ret = asprintf(&entry_str, "test_a/test");
+
+ if (ret <= 0)
+ return NULL;
+
+ return entry_str;
+}
+
+static char *get_event_name(struct kshark_data_stream *stream,
+ const struct kshark_entry *entry)
+{
+ char *evt_str;
+ int ret;
+
+ ret = asprintf(&evt_str, "test_a/event-%i", entry->event_id);
+
+ if (ret <= 0)
+ return NULL;
+
+ return evt_str;
+}
+
+int KSHARK_INPUT_INITIALIZER(struct kshark_data_stream *stream)
+{
+ struct kshark_generic_stream_interface *interface;
+
+ stream->interface = interface = calloc(1, sizeof(*interface));
+ if (!interface)
+ return -ENOMEM;
+
+ interface->type = KS_GENERIC_DATA_INTERFACE;
+
+ stream->n_cpus = 2;
+ stream->n_events = 5;
+ stream->idle_pid = 0;
+
+ kshark_hash_id_add(stream->tasks, 10);
+ kshark_hash_id_add(stream->tasks, 11);
+
+ interface->get_pid = get_pid;
+ interface->get_task = get_task;
+ interface->get_event_name = get_event_name;
+
+ interface->dump_entry = dump_entry;
+ interface->load_entries = load_entries;
+
+ return 0;
+}
+
+void KSHARK_INPUT_DEINITIALIZER(struct kshark_data_stream *stream)
+{}
diff --git a/tests/test-input_ctrl.c b/tests/test-input_ctrl.c
new file mode 100644
index 00000000..3dcc92e7
--- /dev/null
+++ b/tests/test-input_ctrl.c
@@ -0,0 +1,140 @@
+
+// C
+#ifndef _GNU_SOURCE
+/** Use GNU C Library. */
+#define _GNU_SOURCE
+#endif // _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+// KernelShark
+#include "libkshark.h"
+#include "libkshark-plugin.h"
+
+static ssize_t load_entries(struct kshark_data_stream *stream,
+ struct kshark_context *kshark_ctx,
+ struct kshark_entry ***data_rows)
+{
+ struct kshark_entry **rows;
+ ssize_t total = 100, i;
+
+ rows = calloc(total, sizeof(struct kshark_entry *));
+ for (i = 0; i < total; ++i) {
+ rows[i] = calloc(1, sizeof(struct kshark_entry));
+ rows[i]->ts = 1000 + i * 15000;
+ rows[i]->stream_id = stream->stream_id;
+ rows[i]->event_id = i % 3;
+ rows[i]->pid = 20;
+ rows[i]->visible = 0xff;
+ }
+
+ rows[i-1]->pid = 0;
+
+ *data_rows = rows;
+ return total;
+}
+
+static char *dump_entry(struct kshark_data_stream *stream,
+ const struct kshark_entry *entry)
+{
+ char *entry_str;
+ int ret;
+
+ ret = asprintf(&entry_str, "e: time=%li evt=%i s_id=%i", entry->ts,
+ entry->event_id,
+ entry->stream_id);
+
+ if (ret <= 0)
+ return NULL;
+
+ return entry_str;
+}
+
+static const char *format_name = "format_b";
+// static const char *format_name = "tep data";
+
+const char *KSHARK_INPUT_FORMAT()
+{
+ return format_name;
+}
+
+bool KSHARK_INPUT_CHECK(const char *file, char **format)
+{
+ char *ext = strrchr(file, '.');
+
+ if (ext && strcmp(ext, ".tb") == 0)
+ return true;
+
+ return false;
+}
+
+static const int get_pid(struct kshark_data_stream *stream,
+ const struct kshark_entry *entry)
+{
+ return entry->pid;
+}
+
+static char *get_task(struct kshark_data_stream *stream,
+ const struct kshark_entry *entry)
+{
+ char *entry_str;
+ int ret;
+
+ ret = asprintf(&entry_str, "test_b/test");
+
+ if (ret <= 0)
+ return NULL;
+
+ return entry_str;
+}
+
+static char *get_event_name(struct kshark_data_stream *stream,
+ const struct kshark_entry *entry)
+{
+ char *evt_str;
+ int ret;
+
+ ret = asprintf(&evt_str, "test_b/event-%i", entry->event_id);
+
+ if (ret <= 0)
+ return NULL;
+
+ return evt_str;
+}
+
+int KSHARK_INPUT_INITIALIZER(struct kshark_data_stream *stream)
+{
+ struct kshark_generic_stream_interface *interface;
+
+ stream->interface = interface = calloc(1, sizeof(*interface));
+ if (!interface)
+ return -ENOMEM;
+
+ interface->type = KS_GENERIC_DATA_INTERFACE;
+
+ stream->n_cpus = 1;
+ stream->n_events = 3;
+ stream->idle_pid = 0;
+
+ kshark_hash_id_add(stream->tasks, 20);
+
+ interface->get_pid = get_pid;
+ interface->get_task = get_task;
+ interface->get_event_name = get_event_name;
+ interface->dump_entry = dump_entry;
+ interface->load_entries = load_entries;
+
+ return 0;
+}
+
+void KSHARK_INPUT_DEINITIALIZER(struct kshark_data_stream *stream)
+{}
+
+/** Initialize the control interface of the plugin. */
+void *KSHARK_MENU_PLUGIN_INITIALIZER(void *ptr)
+{
+ return NULL;
+}
diff --git a/tests/test-plugin_dpi.c b/tests/test-plugin_dpi.c
new file mode 100644
index 00000000..82f94f38
--- /dev/null
+++ b/tests/test-plugin_dpi.c
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: LGPL-2.1
+
+/*
+ * Copyright (C) 2021 VMware Inc, Yordan Karadzhov <ykaradzhov@vmware.com>
+ */
+
+// C
+#include <stdio.h>
+
+// KernelShark
+#include "libkshark.h"
+#include "libkshark-plugin.h"
+
+/** Load this plugin. */
+int KSHARK_PLOT_PLUGIN_INITIALIZER(struct kshark_data_stream *stream)
+{
+ printf("--> plugin1\n");
+ return 1;
+}
+
+/** Unload this plugin. */
+int KSHARK_PLOT_PLUGIN_DEINITIALIZER(struct kshark_data_stream *stream)
+{
+ printf("<-- plugin1\n");
+ return 1;
+}
diff --git a/tests/test-plugin_dpi_ctrl.c b/tests/test-plugin_dpi_ctrl.c
new file mode 100644
index 00000000..5fafd1da
--- /dev/null
+++ b/tests/test-plugin_dpi_ctrl.c
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: LGPL-2.1
+
+/*
+ * Copyright (C) 2021 VMware Inc, Yordan Karadzhov <ykaradzhov@vmware.com>
+ */
+
+// C
+#include <stdio.h>
+
+// KernelShark
+#include "libkshark.h"
+#include "libkshark-plugin.h"
+
+/** Load this plugin. */
+int KSHARK_PLOT_PLUGIN_INITIALIZER(struct kshark_data_stream *stream)
+{
+ printf("--> plugin2\n");
+ return 2;
+}
+
+/** Unload this plugin. */
+int KSHARK_PLOT_PLUGIN_DEINITIALIZER(struct kshark_data_stream *stream)
+{
+ printf("<-- plugin2\n");
+ return 2;
+}
+
+/** Initialize the control interface of the plugin. */
+void *KSHARK_MENU_PLUGIN_INITIALIZER(void *ptr)
+{
+ return NULL;
+}
diff --git a/tests/test-plugin_dpi_err.c b/tests/test-plugin_dpi_err.c
new file mode 100644
index 00000000..41489304
--- /dev/null
+++ b/tests/test-plugin_dpi_err.c
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: LGPL-2.1
+
+/*
+ * Copyright (C) 2021 VMware Inc, Yordan Karadzhov <ykaradzhov@vmware.com>
+ */
+
+// C
+#include <stdio.h>
+
+// KernelShark
+#include "libkshark.h"
+#include "libkshark-plugin.h"
+
+/** Load this plugin. */
+int KSHARK_PLOT_PLUGIN_INITIALIZER(struct kshark_data_stream *stream)
+{
+ printf("--> plugin_err\n");
+ return 0;
+}
+
+/** Unload this plugin. */
+int KSHARK_PLOT_PLUGIN_DEINITIALIZER(struct kshark_data_stream *stream)
+{
+ printf("<-- plugin_err\n");
+ return 0;
+}