package plugins import ( "os" "path/filepath" "testing" "github.com/stretchr/testify/assert" ) func TestNewPluginLoader(t *testing.T) { registry := NewPluginRegistry() loader := NewPluginLoader(registry, "/tmp/plugins") assert.NotNil(t, loader) assert.Equal(t, registry, loader.registry) } func TestRegisterLoadedPlugin(t *testing.T) { registry := NewPluginRegistry() loader := NewPluginLoader(registry, "/tmp/plugins") plugin := &MockPlugin{name: "test-plugin", version: "1.0.0"} err := loader.RegisterLoadedPlugin(plugin, "test-author", nil) assert.NoError(t, err) assert.True(t, loader.IsPluginLoaded("test-plugin")) } func TestUnloadPlugin(t *testing.T) { registry := NewPluginRegistry() loader := NewPluginLoader(registry, "/tmp/plugins") plugin := &MockPlugin{name: "test-plugin", version: "1.0.0"} loader.RegisterLoadedPlugin(plugin, "test-author", nil) assert.True(t, loader.IsPluginLoaded("test-plugin")) err := loader.UnloadPlugin("test-plugin") assert.NoError(t, err) assert.False(t, loader.IsPluginLoaded("test-plugin")) } func TestUnloadPluginNotFound(t *testing.T) { registry := NewPluginRegistry() loader := NewPluginLoader(registry, "/tmp/plugins") err := loader.UnloadPlugin("nonexistent") assert.Error(t, err) } func TestReloadPlugin(t *testing.T) { registry := NewPluginRegistry() loader := NewPluginLoader(registry, "/tmp/plugins") plugin := &MockPlugin{name: "test-plugin", version: "1.0.0"} loader.RegisterLoadedPlugin(plugin, "test-author", nil) _, _ = loader.GetLoadTime("test-plugin") err := loader.ReloadPlugin("test-plugin") assert.NoError(t, err) loadedPlugins := loader.GetLoadedPlugins() assert.Equal(t, 1, loadedPlugins["test-plugin"].ReloadCount) } func TestReloadPluginNotFound(t *testing.T) { registry := NewPluginRegistry() loader := NewPluginLoader(registry, "/tmp/plugins") err := loader.ReloadPlugin("nonexistent") assert.Error(t, err) } func TestGetLoadedPlugins(t *testing.T) { registry := NewPluginRegistry() loader := NewPluginLoader(registry, "/tmp/plugins") for i := 0; i < 3; i++ { plugin := &MockPlugin{ name: string(rune(48 + i)) + "-plugin", version: "1.0.0", } loader.RegisterLoadedPlugin(plugin, "author", nil) } loaded := loader.GetLoadedPlugins() assert.Equal(t, 3, len(loaded)) } func TestGetLoadTime(t *testing.T) { registry := NewPluginRegistry() loader := NewPluginLoader(registry, "/tmp/plugins") plugin := &MockPlugin{name: "test-plugin", version: "1.0.0"} loader.RegisterLoadedPlugin(plugin, "author", nil) loadTime, exists := loader.GetLoadTime("test-plugin") assert.True(t, exists) assert.NotZero(t, loadTime) } func TestIsPluginLoaded(t *testing.T) { registry := NewPluginRegistry() loader := NewPluginLoader(registry, "/tmp/plugins") assert.False(t, loader.IsPluginLoaded("test-plugin")) plugin := &MockPlugin{name: "test-plugin", version: "1.0.0"} loader.RegisterLoadedPlugin(plugin, "author", nil) assert.True(t, loader.IsPluginLoaded("test-plugin")) } func TestLoaderExecutePlugin(t *testing.T) { registry := NewPluginRegistry() loader := NewPluginLoader(registry, "/tmp/plugins") plugin := &MockPlugin{name: "test-plugin", version: "1.0.0"} loader.RegisterLoadedPlugin(plugin, "author", nil) output, err := loader.ExecutePlugin("test-plugin", map[string]interface{}{}) assert.NoError(t, err) assert.NotNil(t, output) } func TestLoaderExecutePluginNotLoaded(t *testing.T) { registry := NewPluginRegistry() loader := NewPluginLoader(registry, "/tmp/plugins") _, err := loader.ExecutePlugin("nonexistent", map[string]interface{}{}) assert.Error(t, err) } func TestGetPluginStats(t *testing.T) { registry := NewPluginRegistry() loader := NewPluginLoader(registry, "/tmp/plugins") plugin := &MockPlugin{name: "test-plugin", version: "1.0.0"} loader.RegisterLoadedPlugin(plugin, "author", nil) stats, err := loader.GetPluginStats("test-plugin") assert.NoError(t, err) assert.NotNil(t, stats) } func TestGetPluginStatsNotLoaded(t *testing.T) { registry := NewPluginRegistry() loader := NewPluginLoader(registry, "/tmp/plugins") _, err := loader.GetPluginStats("nonexistent") assert.Error(t, err) } func TestClose(t *testing.T) { registry := NewPluginRegistry() loader := NewPluginLoader(registry, "/tmp/plugins") for i := 0; i < 3; i++ { plugin := &MockPlugin{ name: string(rune(48+i)) + "-plugin", version: "1.0.0", } loader.RegisterLoadedPlugin(plugin, "author", nil) } assert.Equal(t, 3, len(loader.GetLoadedPlugins())) err := loader.Close() assert.NoError(t, err) assert.Equal(t, 0, len(loader.GetLoadedPlugins())) } func TestGetPluginRegistry(t *testing.T) { registry := NewPluginRegistry() loader := NewPluginLoader(registry, "/tmp/plugins") retrieved := loader.GetPluginRegistry() assert.Equal(t, registry, retrieved) } func TestLoadPlugin(t *testing.T) { tmpDir := t.TempDir() registry := NewPluginRegistry() loader := NewPluginLoader(registry, tmpDir) // For now, test with plugin:// URL (no file loading needed) err := loader.LoadPlugin("plugin://test-plugin") assert.NoError(t, err) } func TestLoadPluginDirectory(t *testing.T) { tmpDir := t.TempDir() registry := NewPluginRegistry() loader := NewPluginLoader(registry, tmpDir) // Create some mock config files configContent := `{ "name": "test-plugin", "version": "1.0.0", "author": "test-author", "path": "test-plugin" }` configFile := filepath.Join(tmpDir, "test-plugin.json") os.WriteFile(configFile, []byte(configContent), 0644) // Load from directory (won't actually load plugins without more setup) err := loader.LoadPluginDirectory(tmpDir) assert.NoError(t, err) } func TestLoadPluginDirectoryNotFound(t *testing.T) { registry := NewPluginRegistry() loader := NewPluginLoader(registry, "/tmp/plugins") err := loader.LoadPluginDirectory("/nonexistent/directory") assert.Error(t, err) } func TestGetFailedLoads(t *testing.T) { tmpDir := t.TempDir() registry := NewPluginRegistry() loader := NewPluginLoader(registry, tmpDir) // Try to load from nonexistent file loader.LoadPlugin(filepath.Join(tmpDir, "nonexistent.json")) failed := loader.GetFailedLoads() assert.Greater(t, len(failed), 0) } func TestMultiplePluginLifecycle(t *testing.T) { registry := NewPluginRegistry() loader := NewPluginLoader(registry, "/tmp/plugins") // Load plugins for i := 0; i < 5; i++ { plugin := &MockPlugin{ name: string(rune(48+i)) + "-plugin", version: "1.0.0", } err := loader.RegisterLoadedPlugin(plugin, "author", nil) assert.NoError(t, err) } assert.Equal(t, 5, len(loader.GetLoadedPlugins())) // Execute plugins for i := 0; i < 5; i++ { name := string(rune(48+i)) + "-plugin" output, err := loader.ExecutePlugin(name, map[string]interface{}{}) assert.NoError(t, err) assert.NotNil(t, output) } // Unload plugins for i := 0; i < 5; i++ { name := string(rune(48+i)) + "-plugin" err := loader.UnloadPlugin(name) assert.NoError(t, err) } assert.Equal(t, 0, len(loader.GetLoadedPlugins())) } func BenchmarkRegisterLoadedPlugin(b *testing.B) { registry := NewPluginRegistry() loader := NewPluginLoader(registry, "/tmp/plugins") for i := 0; i < b.N; i++ { plugin := &MockPlugin{ name: string(rune(48+i%100)) + "-plugin", version: "1.0.0", } loader.RegisterLoadedPlugin(plugin, "author", nil) } } func BenchmarkExecuteLoadedPlugin(b *testing.B) { registry := NewPluginRegistry() loader := NewPluginLoader(registry, "/tmp/plugins") plugin := &MockPlugin{name: "test-plugin", version: "1.0.0"} loader.RegisterLoadedPlugin(plugin, "author", nil) b.ResetTimer() for i := 0; i < b.N; i++ { loader.ExecutePlugin("test-plugin", map[string]interface{}{}) } }