1
2#include "lldb/Core/PluginManager.h"
3
4#include "gtest/gtest.h"
5
6using namespace lldb;
7using namespace lldb_private;
8
9// Mock system runtime plugin create functions.
10// Make them all return different values to avoid the ICF optimization
11// from combining them into the same function. The values returned
12// are not valid SystemRuntime pointers, but they are unique and
13// sufficient for testing.
14SystemRuntime *CreateSystemRuntimePluginA(Process *process) {
15 return (SystemRuntime *)0x1;
16}
17
18SystemRuntime *CreateSystemRuntimePluginB(Process *process) {
19 return (SystemRuntime *)0x2;
20}
21
22SystemRuntime *CreateSystemRuntimePluginC(Process *process) {
23 return (SystemRuntime *)0x3;
24}
25
26// Test class for testing the PluginManager.
27// The PluginManager modifies global state when registering new plugins. This
28// class is intended to undo those modifications in the destructor to give each
29// test a clean slate with no registered plugins at the start of a test.
30class PluginManagerTest : public testing::Test {
31public:
32 // Remove any pre-registered plugins so we have a known starting point.
33 static void SetUpTestSuite() { RemoveAllRegisteredSystemRuntimePlugins(); }
34
35 // Add mock system runtime plugins for testing.
36 void RegisterMockSystemRuntimePlugins() {
37 // Make sure the create functions all have different addresses.
38 ASSERT_NE(CreateSystemRuntimePluginA, CreateSystemRuntimePluginB);
39 ASSERT_NE(CreateSystemRuntimePluginB, CreateSystemRuntimePluginC);
40
41 ASSERT_TRUE(PluginManager::RegisterPlugin("a", "test instance A",
42 CreateSystemRuntimePluginA));
43 ASSERT_TRUE(PluginManager::RegisterPlugin("b", "test instance B",
44 CreateSystemRuntimePluginB));
45 ASSERT_TRUE(PluginManager::RegisterPlugin("c", "test instance C",
46 CreateSystemRuntimePluginC));
47 }
48
49 // Remove any plugins added during the tests.
50 virtual ~PluginManagerTest() override {
51 RemoveAllRegisteredSystemRuntimePlugins();
52 }
53
54protected:
55 std::vector<SystemRuntimeCreateInstance> m_system_runtime_plugins;
56
57 static void RemoveAllRegisteredSystemRuntimePlugins() {
58 // Enable all currently registered plugins so we can get a handle to
59 // their create callbacks in the loop below. Only enabled plugins
60 // are returned from the PluginManager Get*CreateCallbackAtIndex apis.
61 for (const RegisteredPluginInfo &PluginInfo :
62 PluginManager::GetSystemRuntimePluginInfo()) {
63 PluginManager::SetSystemRuntimePluginEnabled(name: PluginInfo.name, enabled: true);
64 }
65
66 // Get a handle to the create call backs for all the registered plugins.
67 std::vector<SystemRuntimeCreateInstance> registered_plugin_callbacks;
68 SystemRuntimeCreateInstance create_callback = nullptr;
69 for (uint32_t idx = 0;
70 (create_callback =
71 PluginManager::GetSystemRuntimeCreateCallbackAtIndex(idx)) !=
72 nullptr;
73 ++idx) {
74 registered_plugin_callbacks.push_back(x: (create_callback));
75 }
76
77 // Remove all currently registered plugins.
78 for (SystemRuntimeCreateInstance create_callback :
79 registered_plugin_callbacks) {
80 PluginManager::UnregisterPlugin(create_callback);
81 }
82 }
83};
84
85// Test basic register functionality.
86TEST_F(PluginManagerTest, RegisterSystemRuntimePlugin) {
87 RegisterMockSystemRuntimePlugins();
88
89 ASSERT_EQ(PluginManager::GetSystemRuntimeCreateCallbackAtIndex(0),
90 CreateSystemRuntimePluginA);
91
92 ASSERT_EQ(PluginManager::GetSystemRuntimeCreateCallbackAtIndex(1),
93 CreateSystemRuntimePluginB);
94
95 ASSERT_EQ(PluginManager::GetSystemRuntimeCreateCallbackAtIndex(2),
96 CreateSystemRuntimePluginC);
97
98 ASSERT_EQ(PluginManager::GetSystemRuntimeCreateCallbackAtIndex(3), nullptr);
99}
100
101// Test basic un-register functionality.
102TEST_F(PluginManagerTest, UnRegisterSystemRuntimePlugin) {
103 RegisterMockSystemRuntimePlugins();
104
105 ASSERT_TRUE(PluginManager::UnregisterPlugin(CreateSystemRuntimePluginB));
106
107 ASSERT_EQ(PluginManager::GetSystemRuntimeCreateCallbackAtIndex(0),
108 CreateSystemRuntimePluginA);
109
110 ASSERT_EQ(PluginManager::GetSystemRuntimeCreateCallbackAtIndex(1),
111 CreateSystemRuntimePluginC);
112
113 ASSERT_EQ(PluginManager::GetSystemRuntimeCreateCallbackAtIndex(2), nullptr);
114}
115
116// Test registered plugin info functionality.
117TEST_F(PluginManagerTest, SystemRuntimePluginInfo) {
118 RegisterMockSystemRuntimePlugins();
119
120 std::vector<RegisteredPluginInfo> plugin_info =
121 PluginManager::GetSystemRuntimePluginInfo();
122 ASSERT_EQ(plugin_info.size(), 3u);
123 ASSERT_EQ(plugin_info[0].name, "a");
124 ASSERT_EQ(plugin_info[0].description, "test instance A");
125 ASSERT_EQ(plugin_info[0].enabled, true);
126 ASSERT_EQ(plugin_info[1].name, "b");
127 ASSERT_EQ(plugin_info[1].description, "test instance B");
128 ASSERT_EQ(plugin_info[1].enabled, true);
129 ASSERT_EQ(plugin_info[2].name, "c");
130 ASSERT_EQ(plugin_info[2].description, "test instance C");
131 ASSERT_EQ(plugin_info[2].enabled, true);
132}
133
134// Test basic un-register functionality.
135TEST_F(PluginManagerTest, UnRegisterSystemRuntimePluginInfo) {
136 RegisterMockSystemRuntimePlugins();
137
138 // Initial plugin info has all three registered plugins.
139 std::vector<RegisteredPluginInfo> plugin_info =
140 PluginManager::GetSystemRuntimePluginInfo();
141 ASSERT_EQ(plugin_info.size(), 3u);
142
143 ASSERT_TRUE(PluginManager::UnregisterPlugin(CreateSystemRuntimePluginB));
144
145 // After un-registering a plugin it should be removed from plugin info.
146 plugin_info = PluginManager::GetSystemRuntimePluginInfo();
147 ASSERT_EQ(plugin_info.size(), 2u);
148 ASSERT_EQ(plugin_info[0].name, "a");
149 ASSERT_EQ(plugin_info[0].enabled, true);
150 ASSERT_EQ(plugin_info[1].name, "c");
151 ASSERT_EQ(plugin_info[1].enabled, true);
152}
153
154// Test plugin disable functionality.
155TEST_F(PluginManagerTest, SystemRuntimePluginDisable) {
156 RegisterMockSystemRuntimePlugins();
157
158 // Disable plugin should succeed.
159 ASSERT_TRUE(PluginManager::SetSystemRuntimePluginEnabled("b", false));
160
161 // Disabling a plugin does not remove it from plugin info.
162 std::vector<RegisteredPluginInfo> plugin_info =
163 PluginManager::GetSystemRuntimePluginInfo();
164 ASSERT_EQ(plugin_info.size(), 3u);
165 ASSERT_EQ(plugin_info[0].name, "a");
166 ASSERT_EQ(plugin_info[0].enabled, true);
167 ASSERT_EQ(plugin_info[1].name, "b");
168 ASSERT_EQ(plugin_info[1].enabled, false);
169 ASSERT_EQ(plugin_info[2].name, "c");
170 ASSERT_EQ(plugin_info[2].enabled, true);
171
172 // Disabling a plugin does remove it from available plugins.
173 ASSERT_EQ(PluginManager::GetSystemRuntimeCreateCallbackAtIndex(0),
174 CreateSystemRuntimePluginA);
175 ASSERT_EQ(PluginManager::GetSystemRuntimeCreateCallbackAtIndex(1),
176 CreateSystemRuntimePluginC);
177 ASSERT_EQ(PluginManager::GetSystemRuntimeCreateCallbackAtIndex(2), nullptr);
178}
179
180// Test plugin disable and enable functionality.
181TEST_F(PluginManagerTest, SystemRuntimePluginDisableThenEnable) {
182 RegisterMockSystemRuntimePlugins();
183
184 // Initially plugin b is available in slot 1.
185 ASSERT_EQ(PluginManager::GetSystemRuntimeCreateCallbackAtIndex(1),
186 CreateSystemRuntimePluginB);
187
188 // Disabling it will remove it from available plugins.
189 ASSERT_TRUE(PluginManager::SetSystemRuntimePluginEnabled("b", false));
190 ASSERT_EQ(PluginManager::GetSystemRuntimeCreateCallbackAtIndex(0),
191 CreateSystemRuntimePluginA);
192 ASSERT_EQ(PluginManager::GetSystemRuntimeCreateCallbackAtIndex(1),
193 CreateSystemRuntimePluginC);
194
195 // We can re-enable the plugin later and it should go back to the original
196 // slot.
197 ASSERT_TRUE(PluginManager::SetSystemRuntimePluginEnabled("b", true));
198 ASSERT_EQ(PluginManager::GetSystemRuntimeCreateCallbackAtIndex(0),
199 CreateSystemRuntimePluginA);
200 ASSERT_EQ(PluginManager::GetSystemRuntimeCreateCallbackAtIndex(1),
201 CreateSystemRuntimePluginB);
202 ASSERT_EQ(PluginManager::GetSystemRuntimeCreateCallbackAtIndex(2),
203 CreateSystemRuntimePluginC);
204
205 // And show up in the plugin info correctly.
206 std::vector<RegisteredPluginInfo> plugin_info =
207 PluginManager::GetSystemRuntimePluginInfo();
208 ASSERT_EQ(plugin_info.size(), 3u);
209 ASSERT_EQ(plugin_info[0].name, "a");
210 ASSERT_EQ(plugin_info[0].enabled, true);
211 ASSERT_EQ(plugin_info[1].name, "b");
212 ASSERT_EQ(plugin_info[1].enabled, true);
213 ASSERT_EQ(plugin_info[2].name, "c");
214 ASSERT_EQ(plugin_info[2].enabled, true);
215}
216
217// Test calling disable on an already disabled plugin is ok.
218TEST_F(PluginManagerTest, SystemRuntimePluginDisableDisabled) {
219 RegisterMockSystemRuntimePlugins();
220
221 // Initial call to disable the plugin should succeed.
222 ASSERT_TRUE(PluginManager::SetSystemRuntimePluginEnabled("b", false));
223
224 // The second call should also succeed because the plugin is already disabled.
225 ASSERT_TRUE(PluginManager::SetSystemRuntimePluginEnabled("b", false));
226
227 // The call to re-enable the plugin should succeed.
228 ASSERT_TRUE(PluginManager::SetSystemRuntimePluginEnabled("b", true));
229
230 // The second call should also succeed since the plugin is already enabled.
231 ASSERT_TRUE(PluginManager::SetSystemRuntimePluginEnabled("b", true));
232}
233
234// Test calling disable on an already disabled plugin is ok.
235TEST_F(PluginManagerTest, SystemRuntimePluginDisableNonExistent) {
236 RegisterMockSystemRuntimePlugins();
237
238 // Both enable and disable should return false for a non-existent plugin.
239 ASSERT_FALSE(
240 PluginManager::SetSystemRuntimePluginEnabled("does_not_exist", true));
241 ASSERT_FALSE(
242 PluginManager::SetSystemRuntimePluginEnabled("does_not_exist", false));
243}
244
245// Test disabling all plugins and then re-enabling them in a different
246// order will restore the original plugin order.
247TEST_F(PluginManagerTest, SystemRuntimePluginDisableAll) {
248 RegisterMockSystemRuntimePlugins();
249
250 // Validate initial state of registered plugins.
251 ASSERT_EQ(PluginManager::GetSystemRuntimeCreateCallbackAtIndex(0),
252 CreateSystemRuntimePluginA);
253 ASSERT_EQ(PluginManager::GetSystemRuntimeCreateCallbackAtIndex(1),
254 CreateSystemRuntimePluginB);
255 ASSERT_EQ(PluginManager::GetSystemRuntimeCreateCallbackAtIndex(2),
256 CreateSystemRuntimePluginC);
257
258 // Disable all the active plugins.
259 ASSERT_TRUE(PluginManager::SetSystemRuntimePluginEnabled("a", false));
260 ASSERT_TRUE(PluginManager::SetSystemRuntimePluginEnabled("b", false));
261 ASSERT_TRUE(PluginManager::SetSystemRuntimePluginEnabled("c", false));
262
263 // Should have no active plugins.
264 ASSERT_EQ(PluginManager::GetSystemRuntimeCreateCallbackAtIndex(0), nullptr);
265 ASSERT_EQ(PluginManager::GetSystemRuntimeCreateCallbackAtIndex(1), nullptr);
266 ASSERT_EQ(PluginManager::GetSystemRuntimeCreateCallbackAtIndex(2), nullptr);
267
268 // And show up in the plugin info correctly.
269 std::vector<RegisteredPluginInfo> plugin_info =
270 PluginManager::GetSystemRuntimePluginInfo();
271 ASSERT_EQ(plugin_info.size(), 3u);
272 ASSERT_EQ(plugin_info[0].name, "a");
273 ASSERT_EQ(plugin_info[0].enabled, false);
274 ASSERT_EQ(plugin_info[1].name, "b");
275 ASSERT_EQ(plugin_info[1].enabled, false);
276 ASSERT_EQ(plugin_info[2].name, "c");
277 ASSERT_EQ(plugin_info[2].enabled, false);
278
279 // Enable plugins in reverse order and validate expected indicies.
280 // They should show up in the original plugin order.
281 ASSERT_TRUE(PluginManager::SetSystemRuntimePluginEnabled("c", true));
282 ASSERT_EQ(PluginManager::GetSystemRuntimeCreateCallbackAtIndex(0),
283 CreateSystemRuntimePluginC);
284
285 ASSERT_TRUE(PluginManager::SetSystemRuntimePluginEnabled("a", true));
286 ASSERT_EQ(PluginManager::GetSystemRuntimeCreateCallbackAtIndex(0),
287 CreateSystemRuntimePluginA);
288 ASSERT_EQ(PluginManager::GetSystemRuntimeCreateCallbackAtIndex(1),
289 CreateSystemRuntimePluginC);
290
291 ASSERT_TRUE(PluginManager::SetSystemRuntimePluginEnabled("b", true));
292 ASSERT_EQ(PluginManager::GetSystemRuntimeCreateCallbackAtIndex(0),
293 CreateSystemRuntimePluginA);
294 ASSERT_EQ(PluginManager::GetSystemRuntimeCreateCallbackAtIndex(1),
295 CreateSystemRuntimePluginB);
296 ASSERT_EQ(PluginManager::GetSystemRuntimeCreateCallbackAtIndex(2),
297 CreateSystemRuntimePluginC);
298}
299
300// Test un-registering a disabled plugin works.
301TEST_F(PluginManagerTest, UnRegisterDisabledSystemRuntimePlugin) {
302 RegisterMockSystemRuntimePlugins();
303
304 // Initial plugin info has all three registered plugins.
305 std::vector<RegisteredPluginInfo> plugin_info =
306 PluginManager::GetSystemRuntimePluginInfo();
307 ASSERT_EQ(plugin_info.size(), 3u);
308
309 // First disable a plugin, then unregister it. Both should succeed.
310 ASSERT_TRUE(PluginManager::SetSystemRuntimePluginEnabled("b", false));
311 ASSERT_TRUE(PluginManager::UnregisterPlugin(CreateSystemRuntimePluginB));
312
313 // After un-registering a plugin it should be removed from plugin info.
314 plugin_info = PluginManager::GetSystemRuntimePluginInfo();
315 ASSERT_EQ(plugin_info.size(), 2u);
316 ASSERT_EQ(plugin_info[0].name, "a");
317 ASSERT_EQ(plugin_info[0].enabled, true);
318 ASSERT_EQ(plugin_info[1].name, "c");
319 ASSERT_EQ(plugin_info[1].enabled, true);
320}
321
322// Test un-registering and then re-registering a plugin will change the order of
323// loaded plugins.
324TEST_F(PluginManagerTest, UnRegisterSystemRuntimePluginChangesOrder) {
325 RegisterMockSystemRuntimePlugins();
326
327 std::vector<RegisteredPluginInfo> plugin_info =
328 PluginManager::GetSystemRuntimePluginInfo();
329 ASSERT_EQ(PluginManager::GetSystemRuntimeCreateCallbackAtIndex(0),
330 CreateSystemRuntimePluginA);
331 ASSERT_EQ(PluginManager::GetSystemRuntimeCreateCallbackAtIndex(1),
332 CreateSystemRuntimePluginB);
333 ASSERT_EQ(PluginManager::GetSystemRuntimeCreateCallbackAtIndex(2),
334 CreateSystemRuntimePluginC);
335
336 ASSERT_EQ(plugin_info.size(), 3u);
337 ASSERT_EQ(plugin_info[0].name, "a");
338 ASSERT_EQ(plugin_info[1].name, "b");
339 ASSERT_EQ(plugin_info[2].name, "c");
340
341 // Unregister and then registering a plugin puts it at the end of the order
342 // list.
343 ASSERT_TRUE(PluginManager::UnregisterPlugin(CreateSystemRuntimePluginB));
344 ASSERT_TRUE(PluginManager::RegisterPlugin("b", "New test instance B",
345 CreateSystemRuntimePluginB));
346
347 // Check the callback indices match as expected.
348 plugin_info = PluginManager::GetSystemRuntimePluginInfo();
349 ASSERT_EQ(PluginManager::GetSystemRuntimeCreateCallbackAtIndex(0),
350 CreateSystemRuntimePluginA);
351 ASSERT_EQ(PluginManager::GetSystemRuntimeCreateCallbackAtIndex(1),
352 CreateSystemRuntimePluginC);
353 ASSERT_EQ(PluginManager::GetSystemRuntimeCreateCallbackAtIndex(2),
354 CreateSystemRuntimePluginB);
355
356 // And plugin info should match as well.
357 ASSERT_EQ(plugin_info.size(), 3u);
358 ASSERT_EQ(plugin_info[0].name, "a");
359 ASSERT_EQ(plugin_info[1].name, "c");
360 ASSERT_EQ(plugin_info[2].name, "b");
361 ASSERT_EQ(plugin_info[2].description, "New test instance B");
362
363 // Disabling and re-enabling the "c" plugin should slot it back
364 // into the middle of the order. Originally it was last, but after
365 // un-registering and re-registering "b" it should now stay in
366 // the middle of the order.
367 ASSERT_TRUE(PluginManager::SetSystemRuntimePluginEnabled("c", false));
368 ASSERT_EQ(PluginManager::GetSystemRuntimeCreateCallbackAtIndex(0),
369 CreateSystemRuntimePluginA);
370 ASSERT_EQ(PluginManager::GetSystemRuntimeCreateCallbackAtIndex(1),
371 CreateSystemRuntimePluginB);
372
373 // And re-enabling
374 ASSERT_TRUE(PluginManager::SetSystemRuntimePluginEnabled("c", true));
375 ASSERT_EQ(PluginManager::GetSystemRuntimeCreateCallbackAtIndex(0),
376 CreateSystemRuntimePluginA);
377 ASSERT_EQ(PluginManager::GetSystemRuntimeCreateCallbackAtIndex(1),
378 CreateSystemRuntimePluginC);
379 ASSERT_EQ(PluginManager::GetSystemRuntimeCreateCallbackAtIndex(2),
380 CreateSystemRuntimePluginB);
381}
382
383TEST_F(PluginManagerTest, MatchPluginName) {
384 PluginNamespace Foo{.name: "foo", .get_info: nullptr, .set_enabled: nullptr};
385 RegisteredPluginInfo Bar{.name: "bar", .description: "bar plugin ", .enabled: true};
386 RegisteredPluginInfo Baz{.name: "baz", .description: "baz plugin ", .enabled: true};
387
388 // Empty pattern matches everything.
389 ASSERT_TRUE(PluginManager::MatchPluginName("", Foo, Bar));
390
391 // Plugin namespace matches all plugins in that namespace.
392 ASSERT_TRUE(PluginManager::MatchPluginName("foo", Foo, Bar));
393 ASSERT_TRUE(PluginManager::MatchPluginName("foo", Foo, Baz));
394
395 // Fully qualified plugin name matches only that plugin.
396 ASSERT_TRUE(PluginManager::MatchPluginName("foo.bar", Foo, Bar));
397 ASSERT_FALSE(PluginManager::MatchPluginName("foo.baz", Foo, Bar));
398
399 // Prefix match should not match.
400 ASSERT_FALSE(PluginManager::MatchPluginName("f", Foo, Bar));
401 ASSERT_FALSE(PluginManager::MatchPluginName("foo.", Foo, Bar));
402 ASSERT_FALSE(PluginManager::MatchPluginName("foo.ba", Foo, Bar));
403}
404
405TEST_F(PluginManagerTest, JsonFormat) {
406 RegisterMockSystemRuntimePlugins();
407
408 // We expect the following JSON output:
409 // {
410 // "system-runtime": [
411 // {
412 // "enabled": true,
413 // "name": "a"
414 // },
415 // {
416 // "enabled": true,
417 // "name": "b"
418 // },
419 // {
420 // "enabled": true,
421 // "name": "c"
422 // }
423 // ]
424 // }
425 llvm::json::Object obj = PluginManager::GetJSON();
426
427 // We should have a "system-runtime" array in the top-level object.
428 llvm::json::Array *maybe_array = obj.getArray(K: "system-runtime");
429 ASSERT_TRUE(maybe_array != nullptr);
430 auto &array = *maybe_array;
431 ASSERT_EQ(array.size(), 3u);
432
433 // Check plugin "a" info.
434 ASSERT_TRUE(array[0].getAsObject() != nullptr);
435 ASSERT_TRUE(array[0].getAsObject()->getString("name") == "a");
436 ASSERT_TRUE(array[0].getAsObject()->getBoolean("enabled") == true);
437
438 // Check plugin "b" info.
439 ASSERT_TRUE(array[1].getAsObject() != nullptr);
440 ASSERT_TRUE(array[1].getAsObject()->getString("name") == "b");
441 ASSERT_TRUE(array[1].getAsObject()->getBoolean("enabled") == true);
442
443 // Check plugin "c" info.
444 ASSERT_TRUE(array[2].getAsObject() != nullptr);
445 ASSERT_TRUE(array[2].getAsObject()->getString("name") == "c");
446 ASSERT_TRUE(array[2].getAsObject()->getBoolean("enabled") == true);
447
448 // Disabling a plugin should be reflected in the JSON output.
449 ASSERT_TRUE(PluginManager::SetSystemRuntimePluginEnabled("b", false));
450 array = *PluginManager::GetJSON().getArray(K: "system-runtime");
451 ASSERT_TRUE(array[0].getAsObject()->getBoolean("enabled") == true);
452 ASSERT_TRUE(array[1].getAsObject()->getBoolean("enabled") == false);
453 ASSERT_TRUE(array[2].getAsObject()->getBoolean("enabled") == true);
454
455 // Un-registering a plugin should be reflected in the JSON output.
456 ASSERT_TRUE(PluginManager::UnregisterPlugin(CreateSystemRuntimePluginB));
457 array = *PluginManager::GetJSON().getArray(K: "system-runtime");
458 ASSERT_EQ(array.size(), 2u);
459 ASSERT_TRUE(array[0].getAsObject()->getString("name") == "a");
460 ASSERT_TRUE(array[1].getAsObject()->getString("name") == "c");
461
462 // Filtering the JSON output should only include the matching plugins.
463 array =
464 *PluginManager::GetJSON(pattern: "system-runtime.c").getArray(K: "system-runtime");
465 ASSERT_EQ(array.size(), 1u);
466 ASSERT_TRUE(array[0].getAsObject()->getString("name") == "c");
467
468 // Empty JSON output is allowed if there are no matching plugins.
469 obj = PluginManager::GetJSON(pattern: "non-existent-plugin");
470 ASSERT_TRUE(obj.empty());
471}
472

Provided by KDAB

Privacy Policy
Improve your Profiling and Debugging skills
Find out more

source code of lldb/unittests/Core/PluginManagerTest.cpp