This patch is the first part in a patch series that will allow enabling/disabling InstrumentationRuntime plugins in a running debug session. This part adds the `--domain` flag to the `enable`, `disable`, `list` sub commands of `plugin` shell command and plumbs the value of this flag to where it will be needed in a subsequent patch. From the user perspective the flag does nothing useful yet because all values passed to the flag except `global` (the default and what represents LLDB's existing behavior) are rejected. Subsequent patches will allow the flag to do something useful. The `--domain` flag adds a notion of "domain" to plugins with respect to their enablement. Previously all plugins were treated as global and have their enablement stored globally. This is despite the fact that some plugins clearly are not global. For example the `instrumentation-runtime` plugins clearly exist on a per-target basis (the instances of the `InstrumentationRuntime` exist in each process). In addition to this plugins being "global" means instances of the `Debugger` instance are not properly isolated from each other. This PR is a stepping stone towards fixing these design problems. The PR introduces three different domains for plugins: * `global` - Enablement of the plugin can be controlled globally. This is the existing behavior of all LLDB plugins. * `debugger` - Enablement of the plugin can be controlled on a per `Debugger` basis. * `target` - Enablement of the plugin can be controlled on a per `Target` basis. These values are encoded in the new `PluginDomainKind` enum. It is important to note that the design in this PR means a plugin can support more than one domain. In particular in future patches when `instrumentation-runtime` plugins gain support for more than just the `global` domain they will support the `debugger` and `target` domain as well. The key reason that the `instrumentation-runtime` plugins need to support more than one domain is that the plugins need a default enablement value **before** the target exists. That default value will need to come from the `global` domain. Architecturally it should probably come from the `debugger` domain instead but refactoring enablement into Debugger instances is much too large a refactor for this patch series and is a problem that can be tackled later. This patch modifies the `PluginNamespace` struct to: * Store the set of domains supported by the namespace and provided some helper methods to determine what is supported. * Store one of two callbacks. Either `SetPluginEnabledGlobalDomain` (the existing function interface used by most plugins) or `SetPluginEnabledAllDomains` (a new interface used by `InstrumentationRuntime` plugins). In this patch the `InstrumentationRuntime` plugins use the new `SetPluginEnabledAllDomains` function interface for enablement (i.e. the interface of `PluginManager::SetInstrumentationRuntimePluginEnabled` has changed) which passes the `Debugger` instance that made the request and the domain the user provided to the `plugin enable` or `plugin disable` command. To make this patch easier to review the `PluginManager::SetInstrumentationRuntimePluginEnabled` function actually rejects all domains except `global` to keep the behavior change down to a minimum. Proper support for enabling/disabling instrumentation-runtime plugins in the `target`, and `debugger` domains will be implemented in a subsequent patch. The `plugin list` command implementations also reject any domain that isn't `global`. Support for other domains will be added in the subsequent patch that adds support for other domains in the `instrumentation-runtime` plugins. The `plugin enable`, `plugin disable`, `plugin list` commands will use the `global` domain by default so that there is no behavior change for existing workflows. Two new shell tests are included that exercise the new code paths: * `command-plugin-enable-disable-domain-flag.test` validates that `--domain global` works for both global-only and multi-domain plugin namespaces, and that `--domain debugger` and `--domain target` are correctly rejected for now. * `command-plugin-list-domain-flag.test` validates the same behavior for the list command in both text and JSON output modes. I am not experienced at adding flags to LLDB shell commands so I had Claude Code write that part and also help write test cases. Assisted-by: Claude Code rdar://167725878
473 lines
18 KiB
C++
473 lines
18 KiB
C++
|
|
#include "lldb/Core/PluginManager.h"
|
|
|
|
#include "gtest/gtest.h"
|
|
|
|
using namespace lldb;
|
|
using namespace lldb_private;
|
|
|
|
// Mock system runtime plugin create functions.
|
|
// Make them all return different values to avoid the ICF optimization
|
|
// from combining them into the same function. The values returned
|
|
// are not valid SystemRuntime pointers, but they are unique and
|
|
// sufficient for testing.
|
|
SystemRuntime *CreateSystemRuntimePluginA(Process *process) {
|
|
return (SystemRuntime *)0x1;
|
|
}
|
|
|
|
SystemRuntime *CreateSystemRuntimePluginB(Process *process) {
|
|
return (SystemRuntime *)0x2;
|
|
}
|
|
|
|
SystemRuntime *CreateSystemRuntimePluginC(Process *process) {
|
|
return (SystemRuntime *)0x3;
|
|
}
|
|
|
|
// Test class for testing the PluginManager.
|
|
// The PluginManager modifies global state when registering new plugins. This
|
|
// class is intended to undo those modifications in the destructor to give each
|
|
// test a clean slate with no registered plugins at the start of a test.
|
|
class PluginManagerTest : public testing::Test {
|
|
public:
|
|
// Remove any pre-registered plugins so we have a known starting point.
|
|
static void SetUpTestSuite() { RemoveAllRegisteredSystemRuntimePlugins(); }
|
|
|
|
// Add mock system runtime plugins for testing.
|
|
void RegisterMockSystemRuntimePlugins() {
|
|
// Make sure the create functions all have different addresses.
|
|
ASSERT_NE(CreateSystemRuntimePluginA, CreateSystemRuntimePluginB);
|
|
ASSERT_NE(CreateSystemRuntimePluginB, CreateSystemRuntimePluginC);
|
|
|
|
ASSERT_TRUE(PluginManager::RegisterPlugin("a", "test instance A",
|
|
CreateSystemRuntimePluginA));
|
|
ASSERT_TRUE(PluginManager::RegisterPlugin("b", "test instance B",
|
|
CreateSystemRuntimePluginB));
|
|
ASSERT_TRUE(PluginManager::RegisterPlugin("c", "test instance C",
|
|
CreateSystemRuntimePluginC));
|
|
}
|
|
|
|
// Remove any plugins added during the tests.
|
|
virtual ~PluginManagerTest() override {
|
|
RemoveAllRegisteredSystemRuntimePlugins();
|
|
}
|
|
|
|
protected:
|
|
llvm::SmallVector<SystemRuntimeCreateInstance> m_system_runtime_plugins;
|
|
|
|
static void RemoveAllRegisteredSystemRuntimePlugins() {
|
|
// Enable all currently registered plugins so we can get a handle to
|
|
// their create callbacks in the loop below. Only enabled plugins
|
|
// are returned from the PluginManager GetSystemRuntimeCreateCallbacks()
|
|
// api.
|
|
for (const RegisteredPluginInfo &PluginInfo :
|
|
PluginManager::GetSystemRuntimePluginInfo()) {
|
|
PluginManager::SetSystemRuntimePluginEnabled(PluginInfo.name, true);
|
|
}
|
|
|
|
// Get a handle to the create call backs for all the registered plugins.
|
|
llvm::SmallVector<SystemRuntimeCreateInstance> registered_plugin_callbacks =
|
|
PluginManager::GetSystemRuntimeCreateCallbacks();
|
|
|
|
// Remove all currently registered plugins.
|
|
for (SystemRuntimeCreateInstance create_callback :
|
|
registered_plugin_callbacks) {
|
|
PluginManager::UnregisterPlugin(create_callback);
|
|
}
|
|
}
|
|
};
|
|
|
|
// Test basic register functionality.
|
|
TEST_F(PluginManagerTest, RegisterSystemRuntimePlugin) {
|
|
RegisterMockSystemRuntimePlugins();
|
|
|
|
auto callbacks = PluginManager::GetSystemRuntimeCreateCallbacks();
|
|
ASSERT_EQ(callbacks.size(), 3u);
|
|
ASSERT_EQ(callbacks[0], CreateSystemRuntimePluginA);
|
|
ASSERT_EQ(callbacks[1], CreateSystemRuntimePluginB);
|
|
ASSERT_EQ(callbacks[2], CreateSystemRuntimePluginC);
|
|
}
|
|
|
|
// Test basic un-register functionality.
|
|
TEST_F(PluginManagerTest, UnRegisterSystemRuntimePlugin) {
|
|
RegisterMockSystemRuntimePlugins();
|
|
|
|
ASSERT_TRUE(PluginManager::UnregisterPlugin(CreateSystemRuntimePluginB));
|
|
|
|
auto callbacks = PluginManager::GetSystemRuntimeCreateCallbacks();
|
|
ASSERT_EQ(callbacks.size(), 2u);
|
|
ASSERT_EQ(callbacks[0], CreateSystemRuntimePluginA);
|
|
ASSERT_EQ(callbacks[1], CreateSystemRuntimePluginC);
|
|
}
|
|
|
|
// Test registered plugin info functionality.
|
|
TEST_F(PluginManagerTest, SystemRuntimePluginInfo) {
|
|
RegisterMockSystemRuntimePlugins();
|
|
|
|
llvm::SmallVector<RegisteredPluginInfo> plugin_info =
|
|
PluginManager::GetSystemRuntimePluginInfo();
|
|
ASSERT_EQ(plugin_info.size(), 3u);
|
|
ASSERT_EQ(plugin_info[0].name, "a");
|
|
ASSERT_EQ(plugin_info[0].description, "test instance A");
|
|
ASSERT_EQ(plugin_info[0].enabled, true);
|
|
ASSERT_EQ(plugin_info[1].name, "b");
|
|
ASSERT_EQ(plugin_info[1].description, "test instance B");
|
|
ASSERT_EQ(plugin_info[1].enabled, true);
|
|
ASSERT_EQ(plugin_info[2].name, "c");
|
|
ASSERT_EQ(plugin_info[2].description, "test instance C");
|
|
ASSERT_EQ(plugin_info[2].enabled, true);
|
|
}
|
|
|
|
// Test basic un-register functionality.
|
|
TEST_F(PluginManagerTest, UnRegisterSystemRuntimePluginInfo) {
|
|
RegisterMockSystemRuntimePlugins();
|
|
|
|
// Initial plugin info has all three registered plugins.
|
|
llvm::SmallVector<RegisteredPluginInfo> plugin_info =
|
|
PluginManager::GetSystemRuntimePluginInfo();
|
|
ASSERT_EQ(plugin_info.size(), 3u);
|
|
|
|
ASSERT_TRUE(PluginManager::UnregisterPlugin(CreateSystemRuntimePluginB));
|
|
|
|
// After un-registering a plugin it should be removed from plugin info.
|
|
plugin_info = PluginManager::GetSystemRuntimePluginInfo();
|
|
ASSERT_EQ(plugin_info.size(), 2u);
|
|
ASSERT_EQ(plugin_info[0].name, "a");
|
|
ASSERT_EQ(plugin_info[0].enabled, true);
|
|
ASSERT_EQ(plugin_info[1].name, "c");
|
|
ASSERT_EQ(plugin_info[1].enabled, true);
|
|
}
|
|
|
|
// Test plugin disable functionality.
|
|
TEST_F(PluginManagerTest, SystemRuntimePluginDisable) {
|
|
RegisterMockSystemRuntimePlugins();
|
|
|
|
// Disable plugin should succeed.
|
|
ASSERT_TRUE(PluginManager::SetSystemRuntimePluginEnabled("b", false));
|
|
|
|
// Disabling a plugin does not remove it from plugin info.
|
|
llvm::SmallVector<RegisteredPluginInfo> plugin_info =
|
|
PluginManager::GetSystemRuntimePluginInfo();
|
|
ASSERT_EQ(plugin_info.size(), 3u);
|
|
ASSERT_EQ(plugin_info[0].name, "a");
|
|
ASSERT_EQ(plugin_info[0].enabled, true);
|
|
ASSERT_EQ(plugin_info[1].name, "b");
|
|
ASSERT_EQ(plugin_info[1].enabled, false);
|
|
ASSERT_EQ(plugin_info[2].name, "c");
|
|
ASSERT_EQ(plugin_info[2].enabled, true);
|
|
|
|
// Disabling a plugin does remove it from available plugins.
|
|
auto callbacks = PluginManager::GetSystemRuntimeCreateCallbacks();
|
|
ASSERT_EQ(callbacks.size(), 2u);
|
|
ASSERT_EQ(callbacks[0], CreateSystemRuntimePluginA);
|
|
ASSERT_EQ(callbacks[1], CreateSystemRuntimePluginC);
|
|
}
|
|
|
|
// Test plugin disable and enable functionality.
|
|
TEST_F(PluginManagerTest, SystemRuntimePluginDisableThenEnable) {
|
|
RegisterMockSystemRuntimePlugins();
|
|
|
|
// Initially plugin b is available in slot 1.
|
|
{
|
|
auto callbacks = PluginManager::GetSystemRuntimeCreateCallbacks();
|
|
ASSERT_EQ(callbacks[1], CreateSystemRuntimePluginB);
|
|
}
|
|
|
|
// Disabling it will remove it from available plugins.
|
|
ASSERT_TRUE(PluginManager::SetSystemRuntimePluginEnabled("b", false));
|
|
{
|
|
auto callbacks = PluginManager::GetSystemRuntimeCreateCallbacks();
|
|
ASSERT_EQ(callbacks.size(), 2u);
|
|
ASSERT_EQ(callbacks[0], CreateSystemRuntimePluginA);
|
|
ASSERT_EQ(callbacks[1], CreateSystemRuntimePluginC);
|
|
}
|
|
|
|
// We can re-enable the plugin later and it should go back to the original
|
|
// slot.
|
|
ASSERT_TRUE(PluginManager::SetSystemRuntimePluginEnabled("b", true));
|
|
{
|
|
auto callbacks = PluginManager::GetSystemRuntimeCreateCallbacks();
|
|
ASSERT_EQ(callbacks.size(), 3u);
|
|
ASSERT_EQ(callbacks[0], CreateSystemRuntimePluginA);
|
|
ASSERT_EQ(callbacks[1], CreateSystemRuntimePluginB);
|
|
ASSERT_EQ(callbacks[2], CreateSystemRuntimePluginC);
|
|
}
|
|
|
|
// And show up in the plugin info correctly.
|
|
llvm::SmallVector<RegisteredPluginInfo> plugin_info =
|
|
PluginManager::GetSystemRuntimePluginInfo();
|
|
ASSERT_EQ(plugin_info.size(), 3u);
|
|
ASSERT_EQ(plugin_info[0].name, "a");
|
|
ASSERT_EQ(plugin_info[0].enabled, true);
|
|
ASSERT_EQ(plugin_info[1].name, "b");
|
|
ASSERT_EQ(plugin_info[1].enabled, true);
|
|
ASSERT_EQ(plugin_info[2].name, "c");
|
|
ASSERT_EQ(plugin_info[2].enabled, true);
|
|
}
|
|
|
|
// Test calling disable on an already disabled plugin is ok.
|
|
TEST_F(PluginManagerTest, SystemRuntimePluginDisableDisabled) {
|
|
RegisterMockSystemRuntimePlugins();
|
|
|
|
// Initial call to disable the plugin should succeed.
|
|
ASSERT_TRUE(PluginManager::SetSystemRuntimePluginEnabled("b", false));
|
|
|
|
// The second call should also succeed because the plugin is already disabled.
|
|
ASSERT_TRUE(PluginManager::SetSystemRuntimePluginEnabled("b", false));
|
|
|
|
// The call to re-enable the plugin should succeed.
|
|
ASSERT_TRUE(PluginManager::SetSystemRuntimePluginEnabled("b", true));
|
|
|
|
// The second call should also succeed since the plugin is already enabled.
|
|
ASSERT_TRUE(PluginManager::SetSystemRuntimePluginEnabled("b", true));
|
|
}
|
|
|
|
// Test calling disable on an already disabled plugin is ok.
|
|
TEST_F(PluginManagerTest, SystemRuntimePluginDisableNonExistent) {
|
|
RegisterMockSystemRuntimePlugins();
|
|
|
|
// Both enable and disable should return false for a non-existent plugin.
|
|
ASSERT_FALSE(
|
|
PluginManager::SetSystemRuntimePluginEnabled("does_not_exist", true));
|
|
ASSERT_FALSE(
|
|
PluginManager::SetSystemRuntimePluginEnabled("does_not_exist", false));
|
|
}
|
|
|
|
// Test disabling all plugins and then re-enabling them in a different
|
|
// order will restore the original plugin order.
|
|
TEST_F(PluginManagerTest, SystemRuntimePluginDisableAll) {
|
|
RegisterMockSystemRuntimePlugins();
|
|
|
|
// Validate initial state of registered plugins.
|
|
{
|
|
auto callbacks = PluginManager::GetSystemRuntimeCreateCallbacks();
|
|
ASSERT_EQ(callbacks.size(), 3u);
|
|
ASSERT_EQ(callbacks[0], CreateSystemRuntimePluginA);
|
|
ASSERT_EQ(callbacks[1], CreateSystemRuntimePluginB);
|
|
ASSERT_EQ(callbacks[2], CreateSystemRuntimePluginC);
|
|
}
|
|
|
|
// Disable all the active plugins.
|
|
ASSERT_TRUE(PluginManager::SetSystemRuntimePluginEnabled("a", false));
|
|
ASSERT_TRUE(PluginManager::SetSystemRuntimePluginEnabled("b", false));
|
|
ASSERT_TRUE(PluginManager::SetSystemRuntimePluginEnabled("c", false));
|
|
|
|
// Should have no active plugins.
|
|
ASSERT_EQ(PluginManager::GetSystemRuntimeCreateCallbacks().size(), 0u);
|
|
|
|
// And show up in the plugin info correctly.
|
|
llvm::SmallVector<RegisteredPluginInfo> plugin_info =
|
|
PluginManager::GetSystemRuntimePluginInfo();
|
|
ASSERT_EQ(plugin_info.size(), 3u);
|
|
ASSERT_EQ(plugin_info[0].name, "a");
|
|
ASSERT_EQ(plugin_info[0].enabled, false);
|
|
ASSERT_EQ(plugin_info[1].name, "b");
|
|
ASSERT_EQ(plugin_info[1].enabled, false);
|
|
ASSERT_EQ(plugin_info[2].name, "c");
|
|
ASSERT_EQ(plugin_info[2].enabled, false);
|
|
|
|
// Enable plugins in reverse order and validate expected indicies.
|
|
// They should show up in the original plugin order.
|
|
ASSERT_TRUE(PluginManager::SetSystemRuntimePluginEnabled("c", true));
|
|
{
|
|
auto callbacks = PluginManager::GetSystemRuntimeCreateCallbacks();
|
|
ASSERT_EQ(callbacks.size(), 1u);
|
|
ASSERT_EQ(callbacks[0], CreateSystemRuntimePluginC);
|
|
}
|
|
|
|
ASSERT_TRUE(PluginManager::SetSystemRuntimePluginEnabled("a", true));
|
|
{
|
|
auto callbacks = PluginManager::GetSystemRuntimeCreateCallbacks();
|
|
ASSERT_EQ(callbacks.size(), 2u);
|
|
ASSERT_EQ(callbacks[0], CreateSystemRuntimePluginA);
|
|
ASSERT_EQ(callbacks[1], CreateSystemRuntimePluginC);
|
|
}
|
|
|
|
ASSERT_TRUE(PluginManager::SetSystemRuntimePluginEnabled("b", true));
|
|
{
|
|
auto callbacks = PluginManager::GetSystemRuntimeCreateCallbacks();
|
|
ASSERT_EQ(callbacks.size(), 3u);
|
|
ASSERT_EQ(callbacks[0], CreateSystemRuntimePluginA);
|
|
ASSERT_EQ(callbacks[1], CreateSystemRuntimePluginB);
|
|
ASSERT_EQ(callbacks[2], CreateSystemRuntimePluginC);
|
|
}
|
|
}
|
|
|
|
// Test un-registering a disabled plugin works.
|
|
TEST_F(PluginManagerTest, UnRegisterDisabledSystemRuntimePlugin) {
|
|
RegisterMockSystemRuntimePlugins();
|
|
|
|
// Initial plugin info has all three registered plugins.
|
|
llvm::SmallVector<RegisteredPluginInfo> plugin_info =
|
|
PluginManager::GetSystemRuntimePluginInfo();
|
|
ASSERT_EQ(plugin_info.size(), 3u);
|
|
|
|
// First disable a plugin, then unregister it. Both should succeed.
|
|
ASSERT_TRUE(PluginManager::SetSystemRuntimePluginEnabled("b", false));
|
|
ASSERT_TRUE(PluginManager::UnregisterPlugin(CreateSystemRuntimePluginB));
|
|
|
|
// After un-registering a plugin it should be removed from plugin info.
|
|
plugin_info = PluginManager::GetSystemRuntimePluginInfo();
|
|
ASSERT_EQ(plugin_info.size(), 2u);
|
|
ASSERT_EQ(plugin_info[0].name, "a");
|
|
ASSERT_EQ(plugin_info[0].enabled, true);
|
|
ASSERT_EQ(plugin_info[1].name, "c");
|
|
ASSERT_EQ(plugin_info[1].enabled, true);
|
|
}
|
|
|
|
// Test un-registering and then re-registering a plugin will change the order of
|
|
// loaded plugins.
|
|
TEST_F(PluginManagerTest, UnRegisterSystemRuntimePluginChangesOrder) {
|
|
RegisterMockSystemRuntimePlugins();
|
|
|
|
llvm::SmallVector<RegisteredPluginInfo> plugin_info =
|
|
PluginManager::GetSystemRuntimePluginInfo();
|
|
{
|
|
auto callbacks = PluginManager::GetSystemRuntimeCreateCallbacks();
|
|
ASSERT_EQ(callbacks.size(), 3u);
|
|
ASSERT_EQ(callbacks[0], CreateSystemRuntimePluginA);
|
|
ASSERT_EQ(callbacks[1], CreateSystemRuntimePluginB);
|
|
ASSERT_EQ(callbacks[2], CreateSystemRuntimePluginC);
|
|
}
|
|
|
|
ASSERT_EQ(plugin_info.size(), 3u);
|
|
ASSERT_EQ(plugin_info[0].name, "a");
|
|
ASSERT_EQ(plugin_info[1].name, "b");
|
|
ASSERT_EQ(plugin_info[2].name, "c");
|
|
|
|
// Unregister and then registering a plugin puts it at the end of the order
|
|
// list.
|
|
ASSERT_TRUE(PluginManager::UnregisterPlugin(CreateSystemRuntimePluginB));
|
|
ASSERT_TRUE(PluginManager::RegisterPlugin("b", "New test instance B",
|
|
CreateSystemRuntimePluginB));
|
|
|
|
// Check the callback indices match as expected.
|
|
plugin_info = PluginManager::GetSystemRuntimePluginInfo();
|
|
{
|
|
auto callbacks = PluginManager::GetSystemRuntimeCreateCallbacks();
|
|
ASSERT_EQ(callbacks.size(), 3u);
|
|
ASSERT_EQ(callbacks[0], CreateSystemRuntimePluginA);
|
|
ASSERT_EQ(callbacks[1], CreateSystemRuntimePluginC);
|
|
ASSERT_EQ(callbacks[2], CreateSystemRuntimePluginB);
|
|
}
|
|
|
|
// And plugin info should match as well.
|
|
ASSERT_EQ(plugin_info.size(), 3u);
|
|
ASSERT_EQ(plugin_info[0].name, "a");
|
|
ASSERT_EQ(plugin_info[1].name, "c");
|
|
ASSERT_EQ(plugin_info[2].name, "b");
|
|
ASSERT_EQ(plugin_info[2].description, "New test instance B");
|
|
|
|
// Disabling and re-enabling the "c" plugin should slot it back
|
|
// into the middle of the order. Originally it was last, but after
|
|
// un-registering and re-registering "b" it should now stay in
|
|
// the middle of the order.
|
|
ASSERT_TRUE(PluginManager::SetSystemRuntimePluginEnabled("c", false));
|
|
{
|
|
auto callbacks = PluginManager::GetSystemRuntimeCreateCallbacks();
|
|
ASSERT_EQ(callbacks.size(), 2u);
|
|
ASSERT_EQ(callbacks[0], CreateSystemRuntimePluginA);
|
|
ASSERT_EQ(callbacks[1], CreateSystemRuntimePluginB);
|
|
}
|
|
|
|
// And re-enabling
|
|
ASSERT_TRUE(PluginManager::SetSystemRuntimePluginEnabled("c", true));
|
|
{
|
|
auto callbacks = PluginManager::GetSystemRuntimeCreateCallbacks();
|
|
ASSERT_EQ(callbacks.size(), 3u);
|
|
ASSERT_EQ(callbacks[0], CreateSystemRuntimePluginA);
|
|
ASSERT_EQ(callbacks[1], CreateSystemRuntimePluginC);
|
|
ASSERT_EQ(callbacks[2], CreateSystemRuntimePluginB);
|
|
}
|
|
}
|
|
|
|
TEST_F(PluginManagerTest, MatchPluginName) {
|
|
auto TmpFn = [](llvm::StringRef, bool) -> bool { return true; };
|
|
PluginNamespace Foo{"foo", nullptr, TmpFn};
|
|
RegisteredPluginInfo Bar{"bar", "bar plugin ", true};
|
|
RegisteredPluginInfo Baz{"baz", "baz plugin ", true};
|
|
|
|
// Empty pattern matches everything.
|
|
ASSERT_TRUE(PluginManager::MatchPluginName("", Foo, Bar));
|
|
|
|
// Plugin namespace matches all plugins in that namespace.
|
|
ASSERT_TRUE(PluginManager::MatchPluginName("foo", Foo, Bar));
|
|
ASSERT_TRUE(PluginManager::MatchPluginName("foo", Foo, Baz));
|
|
|
|
// Fully qualified plugin name matches only that plugin.
|
|
ASSERT_TRUE(PluginManager::MatchPluginName("foo.bar", Foo, Bar));
|
|
ASSERT_FALSE(PluginManager::MatchPluginName("foo.baz", Foo, Bar));
|
|
|
|
// Prefix match should not match.
|
|
ASSERT_FALSE(PluginManager::MatchPluginName("f", Foo, Bar));
|
|
ASSERT_FALSE(PluginManager::MatchPluginName("foo.", Foo, Bar));
|
|
ASSERT_FALSE(PluginManager::MatchPluginName("foo.ba", Foo, Bar));
|
|
}
|
|
|
|
TEST_F(PluginManagerTest, JsonFormat) {
|
|
RegisterMockSystemRuntimePlugins();
|
|
|
|
// We expect the following JSON output:
|
|
// {
|
|
// "system-runtime": [
|
|
// {
|
|
// "enabled": true,
|
|
// "name": "a"
|
|
// },
|
|
// {
|
|
// "enabled": true,
|
|
// "name": "b"
|
|
// },
|
|
// {
|
|
// "enabled": true,
|
|
// "name": "c"
|
|
// }
|
|
// ]
|
|
// }
|
|
llvm::json::Object obj = PluginManager::GetJSON();
|
|
|
|
// We should have a "system-runtime" array in the top-level object.
|
|
llvm::json::Array *maybe_array = obj.getArray("system-runtime");
|
|
ASSERT_TRUE(maybe_array != nullptr);
|
|
auto &array = *maybe_array;
|
|
ASSERT_EQ(array.size(), 3u);
|
|
|
|
// Check plugin "a" info.
|
|
ASSERT_TRUE(array[0].getAsObject() != nullptr);
|
|
ASSERT_TRUE(array[0].getAsObject()->getString("name") == "a");
|
|
ASSERT_TRUE(array[0].getAsObject()->getBoolean("enabled") == true);
|
|
|
|
// Check plugin "b" info.
|
|
ASSERT_TRUE(array[1].getAsObject() != nullptr);
|
|
ASSERT_TRUE(array[1].getAsObject()->getString("name") == "b");
|
|
ASSERT_TRUE(array[1].getAsObject()->getBoolean("enabled") == true);
|
|
|
|
// Check plugin "c" info.
|
|
ASSERT_TRUE(array[2].getAsObject() != nullptr);
|
|
ASSERT_TRUE(array[2].getAsObject()->getString("name") == "c");
|
|
ASSERT_TRUE(array[2].getAsObject()->getBoolean("enabled") == true);
|
|
|
|
// Disabling a plugin should be reflected in the JSON output.
|
|
ASSERT_TRUE(PluginManager::SetSystemRuntimePluginEnabled("b", false));
|
|
array = *PluginManager::GetJSON().getArray("system-runtime");
|
|
ASSERT_TRUE(array[0].getAsObject()->getBoolean("enabled") == true);
|
|
ASSERT_TRUE(array[1].getAsObject()->getBoolean("enabled") == false);
|
|
ASSERT_TRUE(array[2].getAsObject()->getBoolean("enabled") == true);
|
|
|
|
// Un-registering a plugin should be reflected in the JSON output.
|
|
ASSERT_TRUE(PluginManager::UnregisterPlugin(CreateSystemRuntimePluginB));
|
|
array = *PluginManager::GetJSON().getArray("system-runtime");
|
|
ASSERT_EQ(array.size(), 2u);
|
|
ASSERT_TRUE(array[0].getAsObject()->getString("name") == "a");
|
|
ASSERT_TRUE(array[1].getAsObject()->getString("name") == "c");
|
|
|
|
// Filtering the JSON output should only include the matching plugins.
|
|
array =
|
|
*PluginManager::GetJSON("system-runtime.c").getArray("system-runtime");
|
|
ASSERT_EQ(array.size(), 1u);
|
|
ASSERT_TRUE(array[0].getAsObject()->getString("name") == "c");
|
|
|
|
// Empty JSON output is allowed if there are no matching plugins.
|
|
obj = PluginManager::GetJSON("non-existent-plugin");
|
|
ASSERT_TRUE(obj.empty());
|
|
}
|