feat: allow enabling all plugins into a channel
This commit is contained in:
parent
899ac49336
commit
3b09a9dd47
10 changed files with 915 additions and 17 deletions
331
internal/plugin/plugin_test.go
Normal file
331
internal/plugin/plugin_test.go
Normal file
|
@ -0,0 +1,331 @@
|
|||
package plugin
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"git.nakama.town/fmartingr/butterrobot/internal/model"
|
||||
)
|
||||
|
||||
// Mock plugin for testing
|
||||
type testPlugin struct {
|
||||
BasePlugin
|
||||
}
|
||||
|
||||
func (p *testPlugin) OnMessage(msg *model.Message, config map[string]interface{}, cache model.CacheInterface) []*model.MessageAction {
|
||||
return []*model.MessageAction{
|
||||
{
|
||||
Type: model.ActionSendMessage,
|
||||
Message: &model.Message{
|
||||
Text: "test response",
|
||||
Chat: msg.Chat,
|
||||
Channel: msg.Channel,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAvailablePluginIDs(t *testing.T) {
|
||||
// Clear registry before test
|
||||
ClearRegistry()
|
||||
|
||||
// Register test plugins
|
||||
testPlugin1 := &testPlugin{
|
||||
BasePlugin: BasePlugin{
|
||||
ID: "test.plugin1",
|
||||
Name: "Test Plugin 1",
|
||||
},
|
||||
}
|
||||
testPlugin2 := &testPlugin{
|
||||
BasePlugin: BasePlugin{
|
||||
ID: "test.plugin2",
|
||||
Name: "Test Plugin 2",
|
||||
},
|
||||
}
|
||||
|
||||
Register(testPlugin1)
|
||||
Register(testPlugin2)
|
||||
|
||||
// Test GetAvailablePluginIDs
|
||||
pluginIDs := GetAvailablePluginIDs()
|
||||
|
||||
if len(pluginIDs) != 2 {
|
||||
t.Errorf("Expected 2 plugin IDs, got %d", len(pluginIDs))
|
||||
}
|
||||
|
||||
// Check that both plugin IDs are present
|
||||
found1, found2 := false, false
|
||||
for _, id := range pluginIDs {
|
||||
if id == "test.plugin1" {
|
||||
found1 = true
|
||||
}
|
||||
if id == "test.plugin2" {
|
||||
found2 = true
|
||||
}
|
||||
}
|
||||
|
||||
if !found1 {
|
||||
t.Errorf("Expected to find test.plugin1 in plugin IDs")
|
||||
}
|
||||
if !found2 {
|
||||
t.Errorf("Expected to find test.plugin2 in plugin IDs")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnableAllPluginsProcessingLogic(t *testing.T) {
|
||||
// Clear registry before test
|
||||
ClearRegistry()
|
||||
|
||||
// Register test plugins
|
||||
testPlugin1 := &testPlugin{
|
||||
BasePlugin: BasePlugin{
|
||||
ID: "ping",
|
||||
Name: "Ping Plugin",
|
||||
},
|
||||
}
|
||||
testPlugin2 := &testPlugin{
|
||||
BasePlugin: BasePlugin{
|
||||
ID: "echo",
|
||||
Name: "Echo Plugin",
|
||||
},
|
||||
}
|
||||
testPlugin3 := &testPlugin{
|
||||
BasePlugin: BasePlugin{
|
||||
ID: "help",
|
||||
Name: "Help Plugin",
|
||||
},
|
||||
}
|
||||
|
||||
Register(testPlugin1)
|
||||
Register(testPlugin2)
|
||||
Register(testPlugin3)
|
||||
|
||||
t.Run("EnableAllPlugins false - only explicitly enabled plugins", func(t *testing.T) {
|
||||
// Create a channel with EnableAllPlugins = false and only some plugins enabled
|
||||
channel := &model.Channel{
|
||||
ID: 1,
|
||||
Platform: "telegram",
|
||||
PlatformChannelID: "123456",
|
||||
Enabled: true,
|
||||
EnableAllPlugins: false,
|
||||
Plugins: map[string]*model.ChannelPlugin{
|
||||
"ping": {
|
||||
ID: 1,
|
||||
ChannelID: 1,
|
||||
PluginID: "ping",
|
||||
Enabled: true,
|
||||
Config: map[string]interface{}{"key": "value"},
|
||||
},
|
||||
"echo": {
|
||||
ID: 2,
|
||||
ChannelID: 1,
|
||||
PluginID: "echo",
|
||||
Enabled: false, // Disabled
|
||||
Config: map[string]interface{}{},
|
||||
},
|
||||
// help plugin not configured
|
||||
},
|
||||
}
|
||||
|
||||
// Simulate the plugin processing logic from handleMessage
|
||||
var pluginsToProcess []string
|
||||
|
||||
if channel.EnableAllPlugins {
|
||||
pluginsToProcess = GetAvailablePluginIDs()
|
||||
} else {
|
||||
for pluginID := range channel.Plugins {
|
||||
if channel.HasEnabledPlugin(pluginID) {
|
||||
pluginsToProcess = append(pluginsToProcess, pluginID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Should only have "ping" since echo is disabled and help is not configured
|
||||
if len(pluginsToProcess) != 1 {
|
||||
t.Errorf("Expected 1 plugin to process, got %d: %v", len(pluginsToProcess), pluginsToProcess)
|
||||
}
|
||||
|
||||
if len(pluginsToProcess) > 0 && pluginsToProcess[0] != "ping" {
|
||||
t.Errorf("Expected ping plugin to be processed, got %s", pluginsToProcess[0])
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("EnableAllPlugins true - all registered plugins", func(t *testing.T) {
|
||||
// Create a channel with EnableAllPlugins = true
|
||||
channel := &model.Channel{
|
||||
ID: 1,
|
||||
Platform: "telegram",
|
||||
PlatformChannelID: "123456",
|
||||
Enabled: true,
|
||||
EnableAllPlugins: true,
|
||||
Plugins: map[string]*model.ChannelPlugin{
|
||||
"ping": {
|
||||
ID: 1,
|
||||
ChannelID: 1,
|
||||
PluginID: "ping",
|
||||
Enabled: true,
|
||||
Config: map[string]interface{}{"key": "value"},
|
||||
},
|
||||
"echo": {
|
||||
ID: 2,
|
||||
ChannelID: 1,
|
||||
PluginID: "echo",
|
||||
Enabled: false, // Disabled, but should still be processed
|
||||
Config: map[string]interface{}{},
|
||||
},
|
||||
// help plugin not configured, but should still be processed
|
||||
},
|
||||
}
|
||||
|
||||
// Simulate the plugin processing logic from handleMessage
|
||||
var pluginsToProcess []string
|
||||
|
||||
if channel.EnableAllPlugins {
|
||||
pluginsToProcess = GetAvailablePluginIDs()
|
||||
} else {
|
||||
for pluginID := range channel.Plugins {
|
||||
if channel.HasEnabledPlugin(pluginID) {
|
||||
pluginsToProcess = append(pluginsToProcess, pluginID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Should have all 3 registered plugins
|
||||
if len(pluginsToProcess) != 3 {
|
||||
t.Errorf("Expected 3 plugins to process, got %d: %v", len(pluginsToProcess), pluginsToProcess)
|
||||
}
|
||||
|
||||
// Check that all plugins are included
|
||||
expectedPlugins := map[string]bool{"ping": false, "echo": false, "help": false}
|
||||
for _, pluginID := range pluginsToProcess {
|
||||
if _, exists := expectedPlugins[pluginID]; exists {
|
||||
expectedPlugins[pluginID] = true
|
||||
} else {
|
||||
t.Errorf("Unexpected plugin in processing list: %s", pluginID)
|
||||
}
|
||||
}
|
||||
|
||||
for pluginID, found := range expectedPlugins {
|
||||
if !found {
|
||||
t.Errorf("Expected plugin %s to be in processing list", pluginID)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Plugin configuration handling", func(t *testing.T) {
|
||||
// Test the configuration logic from handleMessage
|
||||
channel := &model.Channel{
|
||||
ID: 1,
|
||||
Platform: "telegram",
|
||||
PlatformChannelID: "123456",
|
||||
Enabled: true,
|
||||
EnableAllPlugins: true,
|
||||
Plugins: map[string]*model.ChannelPlugin{
|
||||
"ping": {
|
||||
ID: 1,
|
||||
ChannelID: 1,
|
||||
PluginID: "ping",
|
||||
Enabled: true,
|
||||
Config: map[string]interface{}{"configured": "value"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
pluginID string
|
||||
expectedConfig map[string]interface{}
|
||||
}{
|
||||
{
|
||||
pluginID: "ping",
|
||||
expectedConfig: map[string]interface{}{"configured": "value"},
|
||||
},
|
||||
{
|
||||
pluginID: "echo", // Not explicitly configured
|
||||
expectedConfig: map[string]interface{}{},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
// Simulate the config retrieval logic from handleMessage
|
||||
var config map[string]interface{}
|
||||
if channelPlugin, exists := channel.Plugins[tc.pluginID]; exists {
|
||||
config = channelPlugin.Config
|
||||
} else {
|
||||
config = make(map[string]interface{})
|
||||
}
|
||||
|
||||
if len(config) != len(tc.expectedConfig) {
|
||||
t.Errorf("Plugin %s: expected config length %d, got %d", tc.pluginID, len(tc.expectedConfig), len(config))
|
||||
}
|
||||
|
||||
for key, expectedValue := range tc.expectedConfig {
|
||||
if actualValue, exists := config[key]; !exists || actualValue != expectedValue {
|
||||
t.Errorf("Plugin %s: expected config[%s] = %v, got %v", tc.pluginID, key, expectedValue, actualValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestPluginRegistry(t *testing.T) {
|
||||
// Clear registry before test
|
||||
ClearRegistry()
|
||||
|
||||
testPlugin := &testPlugin{
|
||||
BasePlugin: BasePlugin{
|
||||
ID: "test.registry",
|
||||
Name: "Test Registry Plugin",
|
||||
},
|
||||
}
|
||||
|
||||
t.Run("Register and Get plugin", func(t *testing.T) {
|
||||
Register(testPlugin)
|
||||
|
||||
retrieved, err := Get("test.registry")
|
||||
if err != nil {
|
||||
t.Errorf("Failed to get registered plugin: %v", err)
|
||||
}
|
||||
|
||||
if retrieved.GetID() != "test.registry" {
|
||||
t.Errorf("Expected plugin ID 'test.registry', got '%s'", retrieved.GetID())
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Get nonexistent plugin", func(t *testing.T) {
|
||||
_, err := Get("nonexistent.plugin")
|
||||
if err == nil {
|
||||
t.Errorf("Expected error when getting nonexistent plugin, got nil")
|
||||
}
|
||||
|
||||
if err != model.ErrPluginNotFound {
|
||||
t.Errorf("Expected ErrPluginNotFound, got %v", err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("GetAvailablePlugins", func(t *testing.T) {
|
||||
plugins := GetAvailablePlugins()
|
||||
|
||||
if len(plugins) != 1 {
|
||||
t.Errorf("Expected 1 plugin in registry, got %d", len(plugins))
|
||||
}
|
||||
|
||||
if plugin, exists := plugins["test.registry"]; !exists {
|
||||
t.Errorf("Expected to find test.registry in available plugins")
|
||||
} else if plugin.GetID() != "test.registry" {
|
||||
t.Errorf("Expected plugin ID 'test.registry', got '%s'", plugin.GetID())
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("ClearRegistry", func(t *testing.T) {
|
||||
ClearRegistry()
|
||||
|
||||
plugins := GetAvailablePlugins()
|
||||
if len(plugins) != 0 {
|
||||
t.Errorf("Expected 0 plugins after clearing registry, got %d", len(plugins))
|
||||
}
|
||||
|
||||
_, err := Get("test.registry")
|
||||
if err == nil {
|
||||
t.Errorf("Expected error when getting plugin after clearing registry, got nil")
|
||||
}
|
||||
})
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue