409 lines
9.7 KiB
Go
409 lines
9.7 KiB
Go
package plugins
|
|||
|
|
|
||
|
|
import (
|
||
|
|
"fmt"
|
||
|
|
"testing"
|
||
|
|
"time"
|
||
|
|
|
||
|
|
"github.com/stretchr/testify/assert"
|
||
|
|
)
|
||
|
|
|
||
|
|
// MockPlugin is a test plugin implementation
|
||
|
|
type MockPlugin struct {
|
||
|
|
name string
|
||
|
|
version string
|
||
|
|
description string
|
||
|
|
shouldFail bool
|
||
|
|
shouldWait time.Duration
|
||
|
|
}
|
||
|
|
|
||
|
|
func (mp *MockPlugin) Name() string {
|
||
|
|
return mp.name
|
||
|
|
}
|
||
|
|
|
||
|
|
func (mp *MockPlugin) Version() string {
|
||
|
|
return mp.version
|
||
|
|
}
|
||
|
|
|
||
|
|
func (mp *MockPlugin) Description() string {
|
||
|
|
return mp.description
|
||
|
|
}
|
||
|
|
|
||
|
|
func (mp *MockPlugin) Execute(input map[string]interface{}) (map[string]interface{}, error) {
|
||
|
|
if mp.shouldWait > 0 {
|
||
|
|
time.Sleep(mp.shouldWait)
|
||
|
|
}
|
||
|
|
|
||
|
|
if mp.shouldFail {
|
||
|
|
return nil, fmt.Errorf("plugin execution failed")
|
||
|
|
}
|
||
|
|
|
||
|
|
return map[string]interface{}{
|
||
|
|
"result": "success",
|
||
|
|
"input": input,
|
||
|
|
}, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func (mp *MockPlugin) Validate() error {
|
||
|
|
if mp.name == "" {
|
||
|
|
return fmt.Errorf("plugin name cannot be empty")
|
||
|
|
}
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestNewPluginRegistry(t *testing.T) {
|
||
|
|
registry := NewPluginRegistry()
|
||
|
|
assert.NotNil(t, registry)
|
||
|
|
assert.Equal(t, 0, registry.stats.TotalPlugins)
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestRegisterPlugin(t *testing.T) {
|
||
|
|
registry := NewPluginRegistry()
|
||
|
|
|
||
|
|
plugin := &MockPlugin{
|
||
|
|
name: "test-plugin",
|
||
|
|
version: "1.0.0",
|
||
|
|
description: "Test plugin",
|
||
|
|
}
|
||
|
|
|
||
|
|
err := registry.Register(plugin, "test-author", nil)
|
||
|
|
assert.NoError(t, err)
|
||
|
|
assert.Equal(t, 1, registry.stats.TotalPlugins)
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestRegisterPluginNil(t *testing.T) {
|
||
|
|
registry := NewPluginRegistry()
|
||
|
|
|
||
|
|
err := registry.Register(nil, "test-author", nil)
|
||
|
|
assert.Error(t, err)
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestRegisterDuplicatePlugin(t *testing.T) {
|
||
|
|
registry := NewPluginRegistry()
|
||
|
|
|
||
|
|
plugin := &MockPlugin{
|
||
|
|
name: "test-plugin",
|
||
|
|
version: "1.0.0",
|
||
|
|
}
|
||
|
|
|
||
|
|
registry.Register(plugin, "author", nil)
|
||
|
|
err := registry.Register(plugin, "author", nil)
|
||
|
|
assert.Error(t, err)
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestUnregisterPlugin(t *testing.T) {
|
||
|
|
registry := NewPluginRegistry()
|
||
|
|
|
||
|
|
plugin := &MockPlugin{name: "test-plugin", version: "1.0.0"}
|
||
|
|
registry.Register(plugin, "author", nil)
|
||
|
|
assert.Equal(t, 1, registry.stats.TotalPlugins)
|
||
|
|
|
||
|
|
err := registry.Unregister("test-plugin")
|
||
|
|
assert.NoError(t, err)
|
||
|
|
assert.Equal(t, 0, registry.stats.TotalPlugins)
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestExecutePlugin(t *testing.T) {
|
||
|
|
registry := NewPluginRegistry()
|
||
|
|
|
||
|
|
plugin := &MockPlugin{name: "test-plugin", version: "1.0.0"}
|
||
|
|
registry.Register(plugin, "author", nil)
|
||
|
|
|
||
|
|
input := map[string]interface{}{"key": "value"}
|
||
|
|
output, err := registry.Execute("test-plugin", input)
|
||
|
|
|
||
|
|
assert.NoError(t, err)
|
||
|
|
assert.NotNil(t, output)
|
||
|
|
assert.Equal(t, "success", output["result"])
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestExecutePluginNotFound(t *testing.T) {
|
||
|
|
registry := NewPluginRegistry()
|
||
|
|
|
||
|
|
_, err := registry.Execute("nonexistent", map[string]interface{}{})
|
||
|
|
assert.Error(t, err)
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestExecutePluginDisabled(t *testing.T) {
|
||
|
|
registry := NewPluginRegistry()
|
||
|
|
|
||
|
|
plugin := &MockPlugin{name: "test-plugin", version: "1.0.0"}
|
||
|
|
registry.Register(plugin, "author", nil)
|
||
|
|
|
||
|
|
registry.DisablePlugin("test-plugin")
|
||
|
|
|
||
|
|
_, err := registry.Execute("test-plugin", map[string]interface{}{})
|
||
|
|
assert.Error(t, err)
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestExecutePluginFailure(t *testing.T) {
|
||
|
|
registry := NewPluginRegistry()
|
||
|
|
|
||
|
|
plugin := &MockPlugin{
|
||
|
|
name: "test-plugin",
|
||
|
|
version: "1.0.0",
|
||
|
|
shouldFail: true,
|
||
|
|
}
|
||
|
|
registry.Register(plugin, "author", nil)
|
||
|
|
|
||
|
|
_, err := registry.Execute("test-plugin", map[string]interface{}{})
|
||
|
|
assert.Error(t, err)
|
||
|
|
assert.Equal(t, 1, registry.stats.FailedExecutions)
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestGetPlugin(t *testing.T) {
|
||
|
|
registry := NewPluginRegistry()
|
||
|
|
|
||
|
|
plugin := &MockPlugin{name: "test-plugin", version: "1.0.0"}
|
||
|
|
registry.Register(plugin, "author", nil)
|
||
|
|
|
||
|
|
retrieved, found := registry.Get("test-plugin")
|
||
|
|
assert.True(t, found)
|
||
|
|
assert.Equal(t, "test-plugin", retrieved.Name())
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestGetPluginNotFound(t *testing.T) {
|
||
|
|
registry := NewPluginRegistry()
|
||
|
|
|
||
|
|
_, found := registry.Get("nonexistent")
|
||
|
|
assert.False(t, found)
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestGetMetadata(t *testing.T) {
|
||
|
|
registry := NewPluginRegistry()
|
||
|
|
|
||
|
|
plugin := &MockPlugin{
|
||
|
|
name: "test-plugin",
|
||
|
|
version: "1.0.0",
|
||
|
|
description: "Test description",
|
||
|
|
}
|
||
|
|
registry.Register(plugin, "test-author", nil)
|
||
|
|
|
||
|
|
meta, found := registry.GetMetadata("test-plugin")
|
||
|
|
assert.True(t, found)
|
||
|
|
assert.Equal(t, "test-plugin", meta.Name)
|
||
|
|
assert.Equal(t, "1.0.0", meta.Version)
|
||
|
|
assert.Equal(t, "test-author", meta.Author)
|
||
|
|
assert.Equal(t, "plugin://test-plugin", meta.URL)
|
||
|
|
assert.True(t, meta.Enabled)
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestListPlugins(t *testing.T) {
|
||
|
|
registry := NewPluginRegistry()
|
||
|
|
|
||
|
|
for i := 0; i < 3; i++ {
|
||
|
|
plugin := &MockPlugin{
|
||
|
|
name: fmt.Sprintf("plugin-%d", i),
|
||
|
|
version: "1.0.0",
|
||
|
|
}
|
||
|
|
registry.Register(plugin, "author", nil)
|
||
|
|
}
|
||
|
|
|
||
|
|
plugins := registry.ListPlugins()
|
||
|
|
assert.Equal(t, 3, len(plugins))
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestEnableDisablePlugin(t *testing.T) {
|
||
|
|
registry := NewPluginRegistry()
|
||
|
|
|
||
|
|
plugin := &MockPlugin{name: "test-plugin", version: "1.0.0"}
|
||
|
|
registry.Register(plugin, "author", nil)
|
||
|
|
|
||
|
|
assert.Equal(t, 1, registry.stats.EnabledPlugins)
|
||
|
|
|
||
|
|
registry.DisablePlugin("test-plugin")
|
||
|
|
assert.Equal(t, 0, registry.stats.EnabledPlugins)
|
||
|
|
|
||
|
|
registry.EnablePlugin("test-plugin")
|
||
|
|
assert.Equal(t, 1, registry.stats.EnabledPlugins)
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestGetExecutionLog(t *testing.T) {
|
||
|
|
registry := NewPluginRegistry()
|
||
|
|
|
||
|
|
plugin := &MockPlugin{name: "test-plugin", version: "1.0.0"}
|
||
|
|
registry.Register(plugin, "author", nil)
|
||
|
|
|
||
|
|
registry.Execute("test-plugin", map[string]interface{}{})
|
||
|
|
registry.Execute("test-plugin", map[string]interface{}{})
|
||
|
|
|
||
|
|
log := registry.GetExecutionLog("test-plugin")
|
||
|
|
assert.Equal(t, 2, len(log))
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestExecutionLogSuccess(t *testing.T) {
|
||
|
|
registry := NewPluginRegistry()
|
||
|
|
|
||
|
|
plugin := &MockPlugin{name: "test-plugin", version: "1.0.0"}
|
||
|
|
registry.Register(plugin, "author", nil)
|
||
|
|
|
||
|
|
registry.Execute("test-plugin", map[string]interface{}{})
|
||
|
|
|
||
|
|
log := registry.GetExecutionLog("test-plugin")
|
||
|
|
assert.Equal(t, 1, len(log))
|
||
|
|
assert.True(t, log[0].Success)
|
||
|
|
assert.Nil(t, log[0].Error)
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestExecutionLogFailure(t *testing.T) {
|
||
|
|
registry := NewPluginRegistry()
|
||
|
|
|
||
|
|
plugin := &MockPlugin{
|
||
|
|
name: "test-plugin",
|
||
|
|
version: "1.0.0",
|
||
|
|
shouldFail: true,
|
||
|
|
}
|
||
|
|
registry.Register(plugin, "author", nil)
|
||
|
|
|
||
|
|
registry.Execute("test-plugin", map[string]interface{}{})
|
||
|
|
|
||
|
|
log := registry.GetExecutionLog("test-plugin")
|
||
|
|
assert.Equal(t, 1, len(log))
|
||
|
|
assert.False(t, log[0].Success)
|
||
|
|
assert.NotNil(t, log[0].Error)
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestGetStats(t *testing.T) {
|
||
|
|
registry := NewPluginRegistry()
|
||
|
|
|
||
|
|
plugin := &MockPlugin{name: "test-plugin", version: "1.0.0"}
|
||
|
|
registry.Register(plugin, "author", nil)
|
||
|
|
|
||
|
|
registry.Execute("test-plugin", map[string]interface{}{})
|
||
|
|
registry.Execute("test-plugin", map[string]interface{}{})
|
||
|
|
|
||
|
|
stats := registry.GetStats()
|
||
|
|
assert.Equal(t, 1, stats.TotalPlugins)
|
||
|
|
assert.Equal(t, 2, stats.TotalExecutions)
|
||
|
|
assert.Equal(t, 2, stats.SuccessfulExecutions)
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestResolvePluginURL(t *testing.T) {
|
||
|
|
registry := NewPluginRegistry()
|
||
|
|
|
||
|
|
plugin := &MockPlugin{name: "test-plugin", version: "1.0.0"}
|
||
|
|
registry.Register(plugin, "author", nil)
|
||
|
|
|
||
|
|
resolved, err := registry.ResolvePluginURL("plugin://test-plugin")
|
||
|
|
assert.NoError(t, err)
|
||
|
|
assert.Equal(t, "test-plugin", resolved.Name())
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestResolvePluginURLInvalid(t *testing.T) {
|
||
|
|
registry := NewPluginRegistry()
|
||
|
|
|
||
|
|
_, err := registry.ResolvePluginURL("http://example.com")
|
||
|
|
assert.Error(t, err)
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestResolvePluginURLNotFound(t *testing.T) {
|
||
|
|
registry := NewPluginRegistry()
|
||
|
|
|
||
|
|
_, err := registry.ResolvePluginURL("plugin://nonexistent")
|
||
|
|
assert.Error(t, err)
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestClear(t *testing.T) {
|
||
|
|
registry := NewPluginRegistry()
|
||
|
|
|
||
|
|
plugin := &MockPlugin{name: "test-plugin", version: "1.0.0"}
|
||
|
|
registry.Register(plugin, "author", nil)
|
||
|
|
|
||
|
|
assert.Equal(t, 1, registry.stats.TotalPlugins)
|
||
|
|
|
||
|
|
registry.Clear()
|
||
|
|
assert.Equal(t, 0, registry.stats.TotalPlugins)
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestIsPluginURL(t *testing.T) {
|
||
|
|
assert.True(t, IsPluginURL("plugin://test"))
|
||
|
|
assert.False(t, IsPluginURL("http://test"))
|
||
|
|
assert.False(t, IsPluginURL("file://test"))
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestExtractPluginName(t *testing.T) {
|
||
|
|
name := ExtractPluginName("plugin://test-plugin")
|
||
|
|
assert.Equal(t, "test-plugin", name)
|
||
|
|
|
||
|
|
name = ExtractPluginName("http://test")
|
||
|
|
assert.Equal(t, "", name)
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestExecutionTiming(t *testing.T) {
|
||
|
|
registry := NewPluginRegistry()
|
||
|
|
|
||
|
|
plugin := &MockPlugin{
|
||
|
|
name: "test-plugin",
|
||
|
|
version: "1.0.0",
|
||
|
|
shouldWait: 50 * time.Millisecond,
|
||
|
|
}
|
||
|
|
registry.Register(plugin, "author", nil)
|
||
|
|
|
||
|
|
registry.Execute("test-plugin", map[string]interface{}{})
|
||
|
|
|
||
|
|
log := registry.GetExecutionLog("test-plugin")
|
||
|
|
assert.Greater(t, log[0].Duration, 40*time.Millisecond)
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestMultiplePlugins(t *testing.T) {
|
||
|
|
registry := NewPluginRegistry()
|
||
|
|
|
||
|
|
for i := 0; i < 5; i++ {
|
||
|
|
plugin := &MockPlugin{
|
||
|
|
name: fmt.Sprintf("plugin-%d", i),
|
||
|
|
version: "1.0.0",
|
||
|
|
}
|
||
|
|
registry.Register(plugin, "author", nil)
|
||
|
|
}
|
||
|
|
|
||
|
|
assert.Equal(t, 5, registry.stats.TotalPlugins)
|
||
|
|
|
||
|
|
for i := 0; i < 5; i++ {
|
||
|
|
registry.Execute(fmt.Sprintf("plugin-%d", i), map[string]interface{}{})
|
||
|
|
}
|
||
|
|
|
||
|
|
stats := registry.GetStats()
|
||
|
|
assert.Equal(t, 5, stats.TotalExecutions)
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestPluginConfig(t *testing.T) {
|
||
|
|
registry := NewPluginRegistry()
|
||
|
|
|
||
|
|
plugin := &MockPlugin{name: "test-plugin", version: "1.0.0"}
|
||
|
|
config := map[string]interface{}{
|
||
|
|
"setting1": "value1",
|
||
|
|
"setting2": 42,
|
||
|
|
}
|
||
|
|
|
||
|
|
registry.Register(plugin, "author", config)
|
||
|
|
|
||
|
|
meta, _ := registry.GetMetadata("test-plugin")
|
||
|
|
assert.NotNil(t, meta.Config)
|
||
|
|
assert.Equal(t, "value1", meta.Config["setting1"])
|
||
|
|
assert.Equal(t, 42, meta.Config["setting2"])
|
||
|
|
}
|
||
|
|
|
||
|
|
func BenchmarkRegisterPlugin(b *testing.B) {
|
||
|
|
registry := NewPluginRegistry()
|
||
|
|
|
||
|
|
for i := 0; i < b.N; i++ {
|
||
|
|
plugin := &MockPlugin{
|
||
|
|
name: fmt.Sprintf("plugin-%d", i),
|
||
|
|
version: "1.0.0",
|
||
|
|
}
|
||
|
|
registry.Register(plugin, "author", nil)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func BenchmarkExecutePlugin(b *testing.B) {
|
||
|
|
registry := NewPluginRegistry()
|
||
|
|
|
||
|
|
plugin := &MockPlugin{name: "test-plugin", version: "1.0.0"}
|
||
|
|
registry.Register(plugin, "author", nil)
|
||
|
|
|
||
|
|
b.ResetTimer()
|
||
|
|
for i := 0; i < b.N; i++ {
|
||
|
|
registry.Execute("test-plugin", map[string]interface{}{})
|
||
|
|
}
|
||
|
|
}
|