eb4fd2ae2397820c07ced439c8933ca215ebe0da
[babeltrace.git] / tests / lib / test_plugin.c
1 /*
2 * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; under version 2 of the License.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16 */
17
18 #include <babeltrace/plugin/plugin.h>
19 #include <babeltrace/object.h>
20 #include <babeltrace/values.h>
21 #include <babeltrace/private-values.h>
22 #include <babeltrace/graph/component.h>
23 #include <babeltrace/graph/private-graph.h>
24 #include <babeltrace/graph/graph.h>
25 #include <babeltrace/graph/query-executor.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <stdio.h>
29 #include <babeltrace/assert-internal.h>
30 #include <glib.h>
31 #include "tap/tap.h"
32 #include "common.h"
33
34 #define NR_TESTS 58
35 #define NON_EXISTING_PATH "/this/hopefully/does/not/exist/5bc75f8d-0dba-4043-a509-d7984b97e42b.so"
36
37 /* Those symbols are written to by some test plugins */
38 static int check_env_var(const char *name)
39 {
40 const char *val = getenv(name);
41
42 if (!val) {
43 return -1;
44 }
45
46 return atoi(val);
47 }
48
49 static void reset_test_plugin_env_vars(void)
50 {
51 g_setenv("BT_TEST_PLUGIN_INIT_CALLED", "0", 1);
52 g_setenv("BT_TEST_PLUGIN_EXIT_CALLED", "0", 1);
53 }
54
55 static char *get_test_plugin_path(const char *plugin_dir,
56 const char *plugin_name)
57 {
58 char *ret;
59 char *plugin_file_name;
60
61 if (asprintf(&plugin_file_name, "plugin-%s." G_MODULE_SUFFIX,
62 plugin_name) == -1) {
63 abort();
64 }
65
66 ret = g_build_filename(plugin_dir, plugin_file_name, NULL);
67 free(plugin_file_name);
68
69 return ret;
70 }
71
72 static void test_invalid(const char *plugin_dir)
73 {
74 struct bt_plugin_set *plugin_set;
75
76 diag("invalid plugin test below");
77
78 plugin_set = bt_plugin_create_all_from_file(NON_EXISTING_PATH);
79 ok(!plugin_set, "bt_plugin_create_all_from_file() fails with a non-existing file");
80
81 plugin_set = bt_plugin_create_all_from_file(plugin_dir);
82 ok(!plugin_set, "bt_plugin_create_all_from_file() fails with a directory");
83
84 ok(!bt_plugin_create_all_from_file(NULL),
85 "bt_plugin_create_all_from_file() handles NULL correctly");
86 ok(!bt_plugin_create_all_from_dir(NULL, BT_FALSE),
87 "bt_plugin_create_all_from_dir() handles NULL correctly");
88 ok(!bt_plugin_get_name(NULL),
89 "bt_plugin_get_name() handles NULL correctly");
90 ok(!bt_plugin_get_description(NULL),
91 "bt_plugin_get_description() handles NULL correctly");
92 ok(bt_plugin_get_version(NULL, NULL, NULL, NULL, NULL) !=
93 BT_PLUGIN_STATUS_OK,
94 "bt_plugin_get_version() handles NULL correctly");
95 ok(!bt_plugin_get_author(NULL),
96 "bt_plugin_get_author() handles NULL correctly");
97 ok(!bt_plugin_get_license(NULL),
98 "bt_plugin_get_license() handles NULL correctly");
99 ok(!bt_plugin_get_path(NULL),
100 "bt_plugin_get_path() handles NULL correctly");
101 ok(bt_plugin_get_component_class_count(NULL) < 0,
102 "bt_plugin_get_component_class_count() handles NULL correctly");
103 ok(!bt_plugin_get_component_class_by_index(NULL, 0),
104 "bt_plugin_get_component_class_by_index() handles NULL correctly");
105 ok(!bt_plugin_get_component_class_by_name_and_type(NULL, NULL, 0),
106 "bt_plugin_get_component_class_by_name_and_type() handles NULL correctly");
107 }
108
109 static void test_minimal(const char *plugin_dir)
110 {
111 struct bt_plugin_set *plugin_set;
112 struct bt_plugin *plugin;
113 char *minimal_path = get_test_plugin_path(plugin_dir, "minimal");
114
115 BT_ASSERT(minimal_path);
116 diag("minimal plugin test below");
117
118 reset_test_plugin_env_vars();
119 plugin_set = bt_plugin_create_all_from_file(minimal_path);
120 ok(plugin_set && bt_plugin_set_get_plugin_count(plugin_set) == 1,
121 "bt_plugin_create_all_from_file() succeeds with a valid file");
122 ok(check_env_var("BT_TEST_PLUGIN_INIT_CALLED") == 1,
123 "plugin's initialization function is called during bt_plugin_create_all_from_file()");
124 ok(bt_plugin_set_get_plugin_count(plugin_set) == 1,
125 "bt_plugin_create_all_from_file() returns the expected number of plugins");
126 plugin = bt_plugin_set_get_plugin(plugin_set, 0);
127 ok(strcmp(bt_plugin_get_name(plugin), "test_minimal") == 0,
128 "bt_plugin_get_name() returns the expected name");
129 ok(strcmp(bt_plugin_get_description(plugin),
130 "Minimal Babeltrace plugin with no component classes") == 0,
131 "bt_plugin_get_description() returns the expected description");
132 ok(bt_plugin_get_version(plugin, NULL, NULL, NULL, NULL) !=
133 BT_PLUGIN_STATUS_OK,
134 "bt_plugin_get_version() fails when there's no version");
135 ok(strcmp(bt_plugin_get_author(plugin), "Janine Sutto") == 0,
136 "bt_plugin_get_author() returns the expected author");
137 ok(strcmp(bt_plugin_get_license(plugin), "Beerware") == 0,
138 "bt_plugin_get_license() returns the expected license");
139 ok(strcmp(bt_plugin_get_path(plugin), minimal_path) == 0,
140 "bt_plugin_get_path() returns the expected path");
141 ok(bt_plugin_get_component_class_count(plugin) == 0,
142 "bt_plugin_get_component_class_count() returns the expected value");
143 bt_object_put_ref(plugin);
144 bt_object_put_ref(plugin_set);
145 ok(check_env_var("BT_TEST_PLUGIN_EXIT_CALLED") == 1,
146 "plugin's exit function is called when the plugin is destroyed");
147
148 free(minimal_path);
149 }
150
151 static void test_sfs(const char *plugin_dir)
152 {
153 struct bt_plugin_set *plugin_set;
154 struct bt_plugin *plugin;
155 struct bt_component_class *sink_comp_class;
156 struct bt_component_class *source_comp_class;
157 struct bt_component_class *filter_comp_class;
158 struct bt_component *sink_component;
159 char *sfs_path = get_test_plugin_path(plugin_dir, "sfs");
160 unsigned int major, minor, patch;
161 const char *extra;
162 struct bt_private_value *params;
163 struct bt_value *results;
164 struct bt_value *object;
165 struct bt_value *res_params;
166 struct bt_private_graph *graph;
167 const char *object_str;
168 enum bt_graph_status graph_ret;
169 struct bt_query_executor *query_exec = bt_query_executor_create();
170 int ret;
171
172 BT_ASSERT(query_exec);
173 BT_ASSERT(sfs_path);
174 diag("sfs plugin test below");
175
176 plugin_set = bt_plugin_create_all_from_file(sfs_path);
177 BT_ASSERT(plugin_set && bt_plugin_set_get_plugin_count(plugin_set) == 1);
178 plugin = bt_plugin_set_get_plugin(plugin_set, 0);
179 ok(bt_plugin_get_version(plugin, &major, &minor, &patch, &extra) ==
180 BT_PLUGIN_STATUS_OK,
181 "bt_plugin_get_version() succeeds when there's a version");
182 ok(major == 1,
183 "bt_plugin_get_version() returns the expected major version");
184 ok(minor == 2,
185 "bt_plugin_get_version() returns the expected minor version");
186 ok(patch == 3,
187 "bt_plugin_get_version() returns the expected patch version");
188 ok(strcmp(extra, "yes") == 0,
189 "bt_plugin_get_version() returns the expected extra version");
190 ok(bt_plugin_get_component_class_count(plugin) == 3,
191 "bt_plugin_get_component_class_count() returns the expected value");
192
193 source_comp_class = bt_plugin_get_component_class_by_name_and_type(
194 plugin, "source", BT_COMPONENT_CLASS_TYPE_SOURCE);
195 ok(source_comp_class,
196 "bt_plugin_get_component_class_by_name_and_type() finds a source component class");
197
198 sink_comp_class = bt_plugin_get_component_class_by_name_and_type(
199 plugin, "sink", BT_COMPONENT_CLASS_TYPE_SINK);
200 ok(sink_comp_class,
201 "bt_plugin_get_component_class_by_name_and_type() finds a sink component class");
202 ok(strcmp(bt_component_class_get_help(sink_comp_class),
203 "Bacon ipsum dolor amet strip steak cupim pastrami venison shoulder.\n"
204 "Prosciutto beef ribs flank meatloaf pancetta brisket kielbasa drumstick\n"
205 "venison tenderloin cow tail. Beef short loin shoulder meatball, sirloin\n"
206 "ground round brisket salami cupim pork bresaola turkey bacon boudin.\n") == 0,
207 "bt_component_class_get_help() returns the expected help text");
208
209 filter_comp_class = bt_plugin_get_component_class_by_name_and_type(
210 plugin, "filter", BT_COMPONENT_CLASS_TYPE_FILTER);
211 ok(filter_comp_class,
212 "bt_plugin_get_component_class_by_name_and_type() finds a filter component class");
213 ok(!bt_plugin_get_component_class_by_name_and_type(plugin, "filter",
214 BT_COMPONENT_CLASS_TYPE_SOURCE),
215 "bt_plugin_get_component_class_by_name_and_type() does not find a component class given the wrong type");
216 params = bt_private_value_integer_create_init(23);
217 BT_ASSERT(params);
218 ret = bt_query_executor_query(NULL, filter_comp_class, "object",
219 bt_value_borrow_from_private(params), &results);
220 ok (ret, "bt_query_executor_query() handles NULL (query executor)");
221 ret = bt_query_executor_query(query_exec, NULL, "object",
222 bt_value_borrow_from_private(params), &results);
223 ok (ret, "bt_query_executor_query() handles NULL (component class)");
224 ret = bt_query_executor_query(query_exec, filter_comp_class, NULL,
225 bt_value_borrow_from_private(params), &results);
226 ok (ret, "bt_query_executor_query() handles NULL (object)");
227 ret = bt_query_executor_query(query_exec, filter_comp_class,
228 "get-something", bt_value_borrow_from_private(params),
229 &results);
230 ok(ret == 0 && results, "bt_query_executor_query() succeeds");
231 BT_ASSERT(bt_value_is_array(results) && bt_value_array_get_size(results) == 2);
232 object = bt_value_array_borrow_element_by_index(results, 0);
233 BT_ASSERT(object && bt_value_is_string(object));
234 object_str = bt_value_string_get(object);
235 ok(strcmp(object_str, "get-something") == 0,
236 "bt_component_class_query() receives the expected object name");
237 res_params = bt_value_array_borrow_element_by_index(results, 1);
238 ok(res_params == bt_value_borrow_from_private(params),
239 "bt_component_class_query() receives the expected parameters");
240
241 diag("> putting the plugin object here");
242 BT_OBJECT_PUT_REF_AND_RESET(plugin);
243 graph = bt_private_graph_create();
244 BT_ASSERT(graph);
245 graph_ret = bt_private_graph_add_component(graph, sink_comp_class, "the-sink",
246 NULL, &sink_component);
247 ok(graph_ret == BT_GRAPH_STATUS_OK && sink_component,
248 "bt_private_graph_add_component() still works after the plugin object is destroyed");
249 BT_OBJECT_PUT_REF_AND_RESET(sink_component);
250 BT_OBJECT_PUT_REF_AND_RESET(source_comp_class);
251 bt_object_put_ref(graph);
252 graph = bt_private_graph_create();
253 BT_ASSERT(graph);
254 graph_ret = bt_private_graph_add_component(graph, sink_comp_class, "the-sink",
255 NULL, &sink_component);
256 ok(graph_ret == BT_GRAPH_STATUS_OK && sink_component,
257 "bt_private_graph_add_component() still works after the source component class object is destroyed");
258 BT_OBJECT_PUT_REF_AND_RESET(sink_component);
259 BT_OBJECT_PUT_REF_AND_RESET(filter_comp_class);
260 bt_object_put_ref(graph);
261 graph = bt_private_graph_create();
262 BT_ASSERT(graph);
263 graph_ret = bt_private_graph_add_component(graph, sink_comp_class, "the-sink",
264 NULL, &sink_component);
265 ok(graph_ret == BT_GRAPH_STATUS_OK && sink_component,
266 "bt_private_graph_add_component() still works after the filter component class object is destroyed");
267 BT_OBJECT_PUT_REF_AND_RESET(sink_comp_class);
268 BT_OBJECT_PUT_REF_AND_RESET(sink_component);
269
270 free(sfs_path);
271 bt_object_put_ref(graph);
272 bt_object_put_ref(plugin_set);
273 bt_object_put_ref(results);
274 bt_object_put_ref(params);
275 bt_object_put_ref(query_exec);
276 }
277
278 static void test_create_all_from_dir(const char *plugin_dir)
279 {
280 struct bt_plugin_set *plugin_set;
281
282 diag("create from all test below");
283
284 plugin_set = bt_plugin_create_all_from_dir(NON_EXISTING_PATH, BT_FALSE);
285 ok(!plugin_set,
286 "bt_plugin_create_all_from_dir() fails with an invalid path");
287
288 plugin_set = bt_plugin_create_all_from_dir(plugin_dir, BT_FALSE);
289 ok(plugin_set, "bt_plugin_create_all_from_dir() succeeds with a valid path");
290
291 /* 2 or 4, if `.la` files are considered or not */
292 ok(bt_plugin_set_get_plugin_count(plugin_set) == 2 ||
293 bt_plugin_set_get_plugin_count(plugin_set) == 4,
294 "bt_plugin_create_all_from_dir() returns the expected number of plugin objects");
295
296 bt_object_put_ref(plugin_set);
297 }
298
299 static void test_find(const char *plugin_dir)
300 {
301 int ret;
302 struct bt_plugin *plugin;
303 struct bt_component_class *comp_cls_sink;
304 struct bt_component_class *comp_cls_source;
305 char *plugin_path;
306
307 ok(!bt_plugin_find(NULL),
308 "bt_plugin_find() handles NULL");
309 ok(!bt_plugin_find(NON_EXISTING_PATH),
310 "bt_plugin_find() returns NULL with an unknown plugin name");
311 ret = asprintf(&plugin_path, "%s" G_SEARCHPATH_SEPARATOR_S
312 G_DIR_SEPARATOR_S "ec1d09e5-696c-442e-b1c3-f9c6cf7f5958"
313 G_SEARCHPATH_SEPARATOR_S G_SEARCHPATH_SEPARATOR_S
314 G_SEARCHPATH_SEPARATOR_S "%s" G_SEARCHPATH_SEPARATOR_S
315 "8db46494-a398-466a-9649-c765ae077629"
316 G_SEARCHPATH_SEPARATOR_S,
317 NON_EXISTING_PATH, plugin_dir);
318 BT_ASSERT(ret > 0 && plugin_path);
319 g_setenv("BABELTRACE_PLUGIN_PATH", plugin_path, 1);
320 plugin = bt_plugin_find("test_minimal");
321 ok(plugin,
322 "bt_plugin_find() succeeds with a plugin name it can find");
323 ok(strcmp(bt_plugin_get_author(plugin), "Janine Sutto") == 0,
324 "bt_plugin_find() finds the correct plugin for a given name");
325 BT_OBJECT_PUT_REF_AND_RESET(plugin);
326 comp_cls_sink = bt_plugin_find_component_class(NULL, "sink",
327 BT_COMPONENT_CLASS_TYPE_SINK);
328 ok(!comp_cls_sink, "bt_plugin_find_component_class() handles NULL (plugin name)");
329 comp_cls_sink = bt_plugin_find_component_class("test_sfs", NULL,
330 BT_COMPONENT_CLASS_TYPE_SINK);
331 ok(!comp_cls_sink, "bt_plugin_find_component_class() handles NULL (component class name)");
332 comp_cls_sink = bt_plugin_find_component_class("test_sfs", "sink2",
333 BT_COMPONENT_CLASS_TYPE_SINK);
334 ok(!comp_cls_sink, "bt_plugin_find_component_class() fails with an unknown component class name");
335 comp_cls_sink = bt_plugin_find_component_class("test_sfs", "sink",
336 BT_COMPONENT_CLASS_TYPE_SINK);
337 ok(comp_cls_sink, "bt_plugin_find_component_class() succeeds with valid parameters");
338 ok(strcmp(bt_component_class_get_name(comp_cls_sink), "sink") == 0,
339 "bt_plugin_find_component_class() returns the appropriate component class (sink)");
340 comp_cls_source = bt_plugin_find_component_class("test_sfs", "source",
341 BT_COMPONENT_CLASS_TYPE_SOURCE);
342 ok(comp_cls_sink, "bt_plugin_find_component_class() succeeds with another component class name (same plugin)");
343 ok(strcmp(bt_component_class_get_name(comp_cls_source), "source") == 0,
344 "bt_plugin_find_component_class() returns the appropriate component class (source)");
345 BT_OBJECT_PUT_REF_AND_RESET(comp_cls_sink);
346 BT_OBJECT_PUT_REF_AND_RESET(comp_cls_source);
347 free(plugin_path);
348 }
349
350 int main(int argc, char **argv)
351 {
352 int ret;
353 const char *plugin_dir;
354
355 if (argc != 2) {
356 puts("Usage: test_plugin plugin_directory");
357 ret = 1;
358 goto end;
359 }
360
361 plugin_dir = argv[1];
362 plan_tests(NR_TESTS);
363 test_invalid(plugin_dir);
364 test_minimal(plugin_dir);
365 test_sfs(plugin_dir);
366 test_create_all_from_dir(plugin_dir);
367 test_find(plugin_dir);
368 ret = exit_status();
369 end:
370 return ret;
371 }
This page took 0.040481 seconds and 3 git commands to generate.