472 lines · cpp
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 optimization11// from combining them into the same function. The values returned12// are not valid SystemRuntime pointers, but they are unique and13// 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. This28// class is intended to undo those modifications in the destructor to give each29// 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 to59 // their create callbacks in the loop below. Only enabled plugins60 // are returned from the PluginManager Get*CreateCallbackAtIndex apis.61 for (const RegisteredPluginInfo &PluginInfo :62 PluginManager::GetSystemRuntimePluginInfo()) {63 PluginManager::SetSystemRuntimePluginEnabled(PluginInfo.name, 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((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 original196 // 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 different246// 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 of323// 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 order342 // 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 back364 // into the middle of the order. Originally it was last, but after365 // un-registering and re-registering "b" it should now stay in366 // 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-enabling374 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{"foo", nullptr, nullptr};385 RegisteredPluginInfo Bar{"bar", "bar plugin ", true};386 RegisteredPluginInfo Baz{"baz", "baz plugin ", 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("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("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("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("system-runtime.c").getArray("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("non-existent-plugin");470 ASSERT_TRUE(obj.empty());471}472