From d0f34f8a125be712051d0ffab621c301922832c8 Mon Sep 17 00:00:00 2001 From: rupinder-syngh Date: Fri, 4 Apr 2025 16:49:20 +0530 Subject: [PATCH] fix: Test cases changes --- pkg/plugin/manager_test.go | 2951 +++++++++++++++++++++++++++--------- 1 file changed, 2268 insertions(+), 683 deletions(-) diff --git a/pkg/plugin/manager_test.go b/pkg/plugin/manager_test.go index c6deae6..30ea826 100644 --- a/pkg/plugin/manager_test.go +++ b/pkg/plugin/manager_test.go @@ -3,11 +3,12 @@ package plugin import ( "archive/zip" "context" - // "errors" - // "fmt" + "errors" + "fmt" "os" "path/filepath" "plugin" + "strings" "testing" "github.com/beckn/beckn-onix/pkg/plugin/definition" @@ -15,7 +16,7 @@ import ( type mockPlugin struct { symbol plugin.Symbol - err error + err error } func (m *mockPlugin) Lookup(str string) (plugin.Symbol, error) { @@ -120,11 +121,11 @@ type mockStepProvider struct { err error } -func (m *mockStepProvider) New(ctx context.Context, config map[string]string) (definition.Step, func() error, error) { +func (m *mockStepProvider) New(ctx context.Context, config map[string]string) (definition.Step, func(), error) { if m.err != nil { return nil, nil, m.err } - return m.step, func() error { return nil }, nil + return m.step, func() {}, nil } // Mock providers for additional interfaces @@ -189,15 +190,15 @@ func (m *mockSignValidatorProvider) New(ctx context.Context, config map[string]s } type mockKeyManagerProvider struct { - manager *mockKeyManager - err error + keyManager *mockKeyManager + err error } func (m *mockKeyManagerProvider) New(ctx context.Context, config map[string]string) (definition.KeyManager, func() error, error) { if m.err != nil { return nil, nil, m.err } - return m.manager, func() error { return nil }, nil + return m.keyManager, func() error { return nil }, nil } // Mock registry lookup for testing @@ -213,57 +214,1131 @@ type testManager struct { cleanup func() } -// func newTestManager() *testManager { -// // Create a temporary directory for testing -// tmpDir, err := os.MkdirTemp("", "plugin-test") -// if err != nil { -// panic(fmt.Sprintf("failed to create temp dir: %v", err)) -// } +// mockValidator is a mock implementation of the Validator interface +type mockValidator struct { + definition.Cache +} -// // Create a test manager with the temporary directory -// ctx := context.Background() -// cfg := &ManagerConfig{ -// Root: tmpDir, -// RemoteRoot: "", -// } -// m, cleanup, err := NewManager(ctx, cfg) -// if err != nil { -// panic(fmt.Sprintf("failed to create manager: %v", err)) -// } +// mockValidatorProvider is a mock implementation of the ValidatorProvider interface +type mockValidatorProvider struct { + validator *mockValidator + err error +} -// tm := &testManager{ -// Manager: m, -// mockProviders: make(map[string]interface{}), -// cleanup: cleanup, -// } +func (m *mockValidatorProvider) New(ctx context.Context, config map[string]string) (definition.Cache, func() error, error) { + if m.err != nil { + return nil, nil, m.err + } + return m.validator, func() error { return nil }, nil +} -// // Initialize the plugins map -// m.plugins = make(map[string]*plugin.Plugin) - -// return tm -// } - -// Test cases -func TestNewManager(t *testing.T) { +// TestNewManager_Success tests the successful scenarios of the NewManager function +func TestNewManager_Success(t *testing.T) { tests := []struct { - name string - cfg *ManagerConfig - wantErr bool + name string + cfg *ManagerConfig }{ { - name: "valid config", + name: "valid config with empty root", cfg: &ManagerConfig{ Root: t.TempDir(), RemoteRoot: "", }, - wantErr: false, }, { - name: "invalid config", + name: "valid config with root path", + cfg: &ManagerConfig{ + Root: t.TempDir(), + RemoteRoot: "", + }, + }, + { + name: "valid config with remote root", + cfg: &ManagerConfig{ + Root: t.TempDir(), + RemoteRoot: "", + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctx := context.Background() + m, cleanup, err := NewManager(ctx, tt.cfg) + if err != nil { + t.Errorf("NewManager() error = %v, want nil", err) + return + } + if m == nil { + t.Error("NewManager() returned nil manager") + return + } + if cleanup == nil { + t.Error("NewManager() returned nil cleanup function") + return + } + + // Verify manager fields + if m.plugins == nil { + t.Error("NewManager() returned manager with nil plugins map") + } + if m.closers == nil { + t.Error("NewManager() returned manager with nil closers slice") + } + + // Call cleanup to ensure it doesn't panic + cleanup() + }) + } +} + +// TestNewManager_Failure tests the failure scenarios of the NewManager function +func TestNewManager_Failure(t *testing.T) { + tests := []struct { + name string + cfg *ManagerConfig + expectedError string + }{ + { + name: "invalid config with nonexistent root", cfg: &ManagerConfig{ Root: "/nonexistent/dir", RemoteRoot: "", }, + expectedError: "no such file or directory", + }, + { + name: "invalid config with nonexistent remote root", + cfg: &ManagerConfig{ + Root: t.TempDir(), + RemoteRoot: "/nonexistent/remote.zip", + }, + expectedError: "no such file or directory", + }, + { + name: "invalid config with permission denied root", + cfg: &ManagerConfig{ + Root: "/root/restricted", + RemoteRoot: "", + }, + expectedError: "permission denied", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctx := context.Background() + m, cleanup, err := NewManager(ctx, tt.cfg) + if err == nil { + t.Error("NewManager() expected error, got nil") + return + } + if !strings.Contains(err.Error(), tt.expectedError) { + t.Errorf("NewManager() error = %v, want error containing %q", err, tt.expectedError) + } + if m != nil { + t.Error("NewManager() returned non-nil manager for error case") + } + if cleanup != nil { + t.Error("NewManager() returned non-nil cleanup function for error case") + } + }) + } +} + +func TestPublisherSuccess(t *testing.T) { + tests := []struct { + name string + publisherID string + mockPublisher *mockPublisher + expectedError error + }{ + { + name: "successful publisher creation", + publisherID: "publisherId", + mockPublisher: &mockPublisher{}, + expectedError: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + errFunc := func() error { return nil } + m := &Manager{ + closers: []func(){}, + plugins: map[string]onixPlugin{ + tt.publisherID: &mockPlugin{ + symbol: &mockPublisherProvider{ + publisher: tt.mockPublisher, + err: errFunc(), + }, + }, + }, + } + + p, err := m.Publisher(context.Background(), &Config{ + ID: tt.publisherID, + Config: map[string]string{}, + }) + + if err != tt.expectedError { + t.Errorf("Manager.Publisher() error = %v, want %v", err, tt.expectedError) + } + + if p != tt.mockPublisher { + t.Errorf("Manager.Publisher() did not return the correct publisher") + } + }) + } +} + +// TestPublisherFailure tests the failure scenarios of the Publisher method +func TestPublisherFailure(t *testing.T) { + tests := []struct { + name string + publisherID string + plugins map[string]onixPlugin + expectedError string + }{ + { + name: "plugin not found", + publisherID: "nonexistent", + plugins: make(map[string]onixPlugin), + expectedError: "plugin nonexistent not found", + }, + { + name: "provider error", + publisherID: "error-provider", + plugins: map[string]onixPlugin{ + "error-provider": &mockPlugin{ + symbol: &mockPublisherProvider{ + publisher: nil, + err: errors.New("provider error"), + }, + }, + }, + expectedError: "provider error", + }, + { + name: "lookup error", + publisherID: "lookup-error", + plugins: map[string]onixPlugin{ + "lookup-error": &mockPlugin{ + symbol: nil, + err: errors.New("lookup failed"), + }, + }, + expectedError: "lookup failed", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + m := &Manager{ + closers: []func(){}, + plugins: tt.plugins, + } + + p, err := m.Publisher(context.Background(), &Config{ + ID: tt.publisherID, + Config: map[string]string{}, + }) + + if err == nil { + t.Error("Manager.Publisher() expected error, got nil") + } else if !strings.Contains(err.Error(), tt.expectedError) { + t.Errorf("Manager.Publisher() error = %v, want error containing %q", err, tt.expectedError) + } + + if p != nil { + t.Error("Manager.Publisher() expected nil publisher, got non-nil") + } + }) + } +} + +// TestManager_SchemaValidator_Success tests the successful scenarios of the SchemaValidator method +func TestManagerSchemaValidatorSuccess(t *testing.T) { + tests := []struct { + name string + cfg *Config + plugin *mockSchemaValidatorProvider + }{ + { + name: "successful validator creation", + cfg: &Config{ + ID: "test-validator", + Config: map[string]string{}, + }, + plugin: &mockSchemaValidatorProvider{ + validator: &mockSchemaValidator{}, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Create a manager with the mock plugin + m := &Manager{ + plugins: map[string]onixPlugin{ + tt.cfg.ID: &mockPlugin{ + symbol: tt.plugin, + }, + }, + closers: []func(){}, + } + + // Call SchemaValidator + validator, err := m.SchemaValidator(context.Background(), tt.cfg) + + // Check success case + if err != nil { + t.Errorf("unexpected error: %v", err) + } + if validator == nil { + t.Error("expected non-nil validator, got nil") + } + }) + } +} + +// TestManager_SchemaValidator_Failure tests the failure scenarios of the SchemaValidator method +func TestManagerSchemaValidatorFailure(t *testing.T) { + tests := []struct { + name string + cfg *Config + plugin *mockSchemaValidatorProvider + expectedError string + }{ + { + name: "provider error", + cfg: &Config{ + ID: "test-validator", + Config: map[string]string{}, + }, + plugin: &mockSchemaValidatorProvider{ + err: errors.New("provider error"), + }, + expectedError: "provider error", + }, + { + name: "plugin not found", + cfg: &Config{ + ID: "nonexistent-validator", + Config: map[string]string{}, + }, + plugin: nil, + expectedError: "plugin nonexistent-validator not found", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Create a manager with the mock plugin + m := &Manager{ + plugins: make(map[string]onixPlugin), + closers: []func(){}, + } + + // Only add the plugin if it's not nil + if tt.plugin != nil { + m.plugins[tt.cfg.ID] = &mockPlugin{ + symbol: tt.plugin, + } + } + + // Call SchemaValidator + validator, err := m.SchemaValidator(context.Background(), tt.cfg) + + // Check error + if err == nil { + t.Error("expected error, got nil") + } else if !strings.Contains(err.Error(), tt.expectedError) { + t.Errorf("error = %v, want error containing %q", err, tt.expectedError) + } + if validator != nil { + t.Error("expected nil validator, got non-nil") + } + }) + } +} + +// TestManager_Router_Success tests the successful scenarios of the Router method +func TestManagerRouterSuccess(t *testing.T) { + tests := []struct { + name string + cfg *Config + plugin *mockRouterProvider + }{ + { + name: "successful router creation", + cfg: &Config{ + ID: "test-router", + Config: map[string]string{}, + }, + plugin: &mockRouterProvider{ + router: &mockRouter{}, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Create a manager with the mock plugin + m := &Manager{ + plugins: map[string]onixPlugin{ + tt.cfg.ID: &mockPlugin{ + symbol: tt.plugin, + }, + }, + closers: []func(){}, + } + + // Call Router + router, err := m.Router(context.Background(), tt.cfg) + + // Check success case + if err != nil { + t.Errorf("unexpected error: %v", err) + } + if router == nil { + t.Error("expected non-nil router, got nil") + } + if router != tt.plugin.router { + t.Error("router does not match expected instance") + } + }) + } +} + +// TestManager_Router_Failure tests the failure scenarios of the Router method +func TestManagerRouterFailure(t *testing.T) { + tests := []struct { + name string + cfg *Config + plugin *mockRouterProvider + expectedError string + }{ + { + name: "provider error", + cfg: &Config{ + ID: "test-router", + Config: map[string]string{}, + }, + plugin: &mockRouterProvider{ + err: errors.New("provider error"), + }, + expectedError: "provider error", + }, + { + name: "plugin not found", + cfg: &Config{ + ID: "nonexistent-router", + Config: map[string]string{}, + }, + plugin: nil, + expectedError: "plugin nonexistent-router not found", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Create a manager with the mock plugin + m := &Manager{ + plugins: make(map[string]onixPlugin), + closers: []func(){}, + } + + // Only add the plugin if it's not nil + if tt.plugin != nil { + m.plugins[tt.cfg.ID] = &mockPlugin{ + symbol: tt.plugin, + } + } + + // Call Router + router, err := m.Router(context.Background(), tt.cfg) + + // Check error + if err == nil { + t.Error("expected error, got nil") + } else if !strings.Contains(err.Error(), tt.expectedError) { + t.Errorf("error = %v, want error containing %q", err, tt.expectedError) + } + if router != nil { + t.Error("expected nil router, got non-nil") + } + }) + } +} + +// TestManager_Step_Success tests the successful scenarios of the Step method +func TestManagerStepSuccess(t *testing.T) { + tests := []struct { + name string + cfg *Config + plugin *mockStepProvider + }{ + { + name: "successful step creation", + cfg: &Config{ + ID: "test-step", + Config: map[string]string{}, + }, + plugin: &mockStepProvider{ + step: &mockStep{}, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Create a manager with the mock plugin + m := &Manager{ + plugins: map[string]onixPlugin{ + tt.cfg.ID: &mockPlugin{ + symbol: tt.plugin, + }, + }, + closers: []func(){}, + } + + // Call Step + step, err := m.Step(context.Background(), tt.cfg) + + // Check success case + if err != nil { + t.Errorf("unexpected error: %v", err) + } + if step == nil { + t.Error("expected non-nil step, got nil") + } + if step != tt.plugin.step { + t.Error("step does not match expected instance") + } + }) + } +} + +// TestManager_Step_Failure tests the failure scenarios of the Step method +func TestManagerStepFailure(t *testing.T) { + tests := []struct { + name string + cfg *Config + plugin *mockStepProvider + expectedError string + }{ + { + name: "provider error", + cfg: &Config{ + ID: "test-step", + Config: map[string]string{}, + }, + plugin: &mockStepProvider{ + err: errors.New("provider error"), + }, + expectedError: "provider error", + }, + { + name: "plugin not found", + cfg: &Config{ + ID: "nonexistent-step", + Config: map[string]string{}, + }, + plugin: nil, + expectedError: "plugin nonexistent-step not found", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Create a manager with the mock plugin + m := &Manager{ + plugins: make(map[string]onixPlugin), + closers: []func(){}, + } + + // Only add the plugin if it's not nil + if tt.plugin != nil { + m.plugins[tt.cfg.ID] = &mockPlugin{ + symbol: tt.plugin, + } + } + + // Call Step + step, err := m.Step(context.Background(), tt.cfg) + + // Check error + if err == nil { + t.Error("expected error, got nil") + } else if !strings.Contains(err.Error(), tt.expectedError) { + t.Errorf("error = %v, want error containing %q", err, tt.expectedError) + } + if step != nil { + t.Error("expected nil step, got non-nil") + } + }) + } +} + +// TestManager_Validator_Success tests the successful scenarios of the Validator method +func TestManager_ValidatorSuccess(t *testing.T) { + tests := []struct { + name string + cfg *Config + plugin *mockValidatorProvider + }{ + { + name: "successful validator creation", + cfg: &Config{ + ID: "test-validator", + Config: map[string]string{}, + }, + plugin: &mockValidatorProvider{ + validator: &mockValidator{}, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Create a manager with the mock plugin + m := &Manager{ + plugins: map[string]onixPlugin{ + tt.cfg.ID: &mockPlugin{ + symbol: tt.plugin, + }, + }, + closers: []func(){}, + } + + // Call Validator + validator, err := m.Validator(context.Background(), tt.cfg) + + // Check success case + if err != nil { + t.Errorf("unexpected error: %v", err) + } + if validator == nil { + t.Error("expected non-nil validator, got nil") + } + }) + } +} + +// TestManager_Validator_Failure tests the failure scenarios of the Validator method +func TestManagerValidatorFailure(t *testing.T) { + tests := []struct { + name string + cfg *Config + plugin *mockValidatorProvider + expectedError string + }{ + { + name: "provider error", + cfg: &Config{ + ID: "test-validator", + Config: map[string]string{}, + }, + plugin: &mockValidatorProvider{ + err: errors.New("provider error"), + }, + expectedError: "provider error", + }, + { + name: "plugin not found", + cfg: &Config{ + ID: "nonexistent-validator", + Config: map[string]string{}, + }, + plugin: nil, + expectedError: "plugin nonexistent-validator not found", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Create a manager with the mock plugin + m := &Manager{ + plugins: make(map[string]onixPlugin), + closers: []func(){}, + } + + // Only add the plugin if it's not nil + if tt.plugin != nil { + m.plugins[tt.cfg.ID] = &mockPlugin{ + symbol: tt.plugin, + } + } + + // Call Validator + validator, err := m.Validator(context.Background(), tt.cfg) + + // Check error + if err == nil { + t.Error("expected error, got nil") + } else if !strings.Contains(err.Error(), tt.expectedError) { + t.Errorf("error = %v, want error containing %q", err, tt.expectedError) + } + if validator != nil { + t.Error("expected nil validator, got non-nil") + } + }) + } +} + +// TestManager_Cache_Success tests the successful scenarios of the Cache method +func TestManagerCacheSuccess(t *testing.T) { + tests := []struct { + name string + cfg *Config + plugin *mockCacheProvider + }{ + { + name: "successful cache creation", + cfg: &Config{ + ID: "test-cache", + Config: map[string]string{}, + }, + plugin: &mockCacheProvider{ + cache: &mockCache{}, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Create a manager with the mock plugin + m := &Manager{ + plugins: map[string]onixPlugin{ + tt.cfg.ID: &mockPlugin{ + symbol: tt.plugin, + }, + }, + closers: []func(){}, + } + + // Call Cache + cache, err := m.Cache(context.Background(), tt.cfg) + + // Check success case + if err != nil { + t.Errorf("unexpected error: %v", err) + } + if cache == nil { + t.Error("expected non-nil cache, got nil") + } + }) + } +} + +// TestManager_Cache_Failure tests the failure scenarios of the Cache method +func TestManagerCacheFailure(t *testing.T) { + tests := []struct { + name string + cfg *Config + plugin *mockCacheProvider + expectedError string + }{ + { + name: "provider error", + cfg: &Config{ + ID: "test-cache", + Config: map[string]string{}, + }, + plugin: &mockCacheProvider{ + err: errors.New("provider error"), + }, + expectedError: "provider error", + }, + { + name: "plugin not found", + cfg: &Config{ + ID: "nonexistent-cache", + Config: map[string]string{}, + }, + plugin: nil, + expectedError: "plugin nonexistent-cache not found", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Create a manager with the mock plugin + m := &Manager{ + plugins: make(map[string]onixPlugin), + closers: []func(){}, + } + + // Only add the plugin if it's not nil + if tt.plugin != nil { + m.plugins[tt.cfg.ID] = &mockPlugin{ + symbol: tt.plugin, + } + } + + // Call Cache + cache, err := m.Cache(context.Background(), tt.cfg) + + // Check error + if err == nil { + t.Error("expected error, got nil") + } else if !strings.Contains(err.Error(), tt.expectedError) { + t.Errorf("error = %v, want error containing %q", err, tt.expectedError) + } + if cache != nil { + t.Error("expected nil cache, got non-nil") + } + }) + } +} + +// TestManager_Signer_Success tests the successful scenarios of the Signer method +func TestManagerSignerSuccess(t *testing.T) { + tests := []struct { + name string + cfg *Config + plugin *mockSignerProvider + }{ + { + name: "successful signer creation", + cfg: &Config{ + ID: "test-signer", + Config: map[string]string{}, + }, + plugin: &mockSignerProvider{ + signer: &mockSigner{}, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Create a manager with the mock plugin + m := &Manager{ + plugins: map[string]onixPlugin{ + tt.cfg.ID: &mockPlugin{ + symbol: tt.plugin, + }, + }, + closers: []func(){}, + } + + // Call Signer + signer, err := m.Signer(context.Background(), tt.cfg) + + // Check success case + if err != nil { + t.Errorf("unexpected error: %v", err) + } + if signer == nil { + t.Error("expected non-nil signer, got nil") + } + }) + } +} + +// TestManager_Signer_Failure tests the failure scenarios of the Signer method +func TestManagerSignerFailure(t *testing.T) { + tests := []struct { + name string + cfg *Config + plugin *mockSignerProvider + expectedError string + }{ + { + name: "provider error", + cfg: &Config{ + ID: "test-signer", + Config: map[string]string{}, + }, + plugin: &mockSignerProvider{ + err: errors.New("provider error"), + }, + expectedError: "provider error", + }, + { + name: "plugin not found", + cfg: &Config{ + ID: "nonexistent-signer", + Config: map[string]string{}, + }, + plugin: nil, + expectedError: "plugin nonexistent-signer not found", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Create a manager with the mock plugin + m := &Manager{ + plugins: make(map[string]onixPlugin), + closers: []func(){}, + } + + // Only add the plugin if it's not nil + if tt.plugin != nil { + m.plugins[tt.cfg.ID] = &mockPlugin{ + symbol: tt.plugin, + } + } + + // Call Signer + signer, err := m.Signer(context.Background(), tt.cfg) + + // Check error + if err == nil { + t.Error("expected error, got nil") + } else if !strings.Contains(err.Error(), tt.expectedError) { + t.Errorf("error = %v, want error containing %q", err, tt.expectedError) + } + if signer != nil { + t.Error("expected nil signer, got non-nil") + } + }) + } +} + +// TestManager_Encryptor_Success tests the successful scenarios of the Encryptor method +func TestManagerEncryptorSuccess(t *testing.T) { + tests := []struct { + name string + cfg *Config + plugin *mockEncrypterProvider + }{ + { + name: "successful encrypter creation", + cfg: &Config{ + ID: "test-encrypter", + Config: map[string]string{}, + }, + plugin: &mockEncrypterProvider{ + encrypter: &mockEncrypter{}, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Create a manager with the mock plugin + m := &Manager{ + plugins: map[string]onixPlugin{ + tt.cfg.ID: &mockPlugin{ + symbol: tt.plugin, + }, + }, + closers: []func(){}, + } + + // Call Encryptor + encrypter, err := m.Encryptor(context.Background(), tt.cfg) + + // Check success case + if err != nil { + t.Errorf("unexpected error: %v", err) + } + if encrypter == nil { + t.Error("expected non-nil encrypter, got nil") + } + }) + } +} + +// TestManager_Encryptor_Failure tests the failure scenarios of the Encryptor method +func TestManagerEncryptorFailure(t *testing.T) { + tests := []struct { + name string + cfg *Config + plugin *mockEncrypterProvider + expectedError string + }{ + { + name: "provider error", + cfg: &Config{ + ID: "test-encrypter", + Config: map[string]string{}, + }, + plugin: &mockEncrypterProvider{ + err: errors.New("provider error"), + }, + expectedError: "provider error", + }, + { + name: "plugin not found", + cfg: &Config{ + ID: "nonexistent-encrypter", + Config: map[string]string{}, + }, + plugin: nil, + expectedError: "plugin nonexistent-encrypter not found", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Create a manager with the mock plugin + m := &Manager{ + plugins: make(map[string]onixPlugin), + closers: []func(){}, + } + + // Only add the plugin if it's not nil + if tt.plugin != nil { + m.plugins[tt.cfg.ID] = &mockPlugin{ + symbol: tt.plugin, + } + } + + // Call Encryptor + encrypter, err := m.Encryptor(context.Background(), tt.cfg) + + // Check error + if err == nil { + t.Error("expected error, got nil") + } else if !strings.Contains(err.Error(), tt.expectedError) { + t.Errorf("error = %v, want error containing %q", err, tt.expectedError) + } + if encrypter != nil { + t.Error("expected nil encrypter, got non-nil") + } + }) + } +} + +// TestManager_Decryptor_Success tests the successful scenarios of the Decryptor method +func TestManagerDecryptorSuccess(t *testing.T) { + tests := []struct { + name string + cfg *Config + plugin *mockDecrypterProvider + }{ + { + name: "successful decrypter creation", + cfg: &Config{ + ID: "test-decrypter", + Config: map[string]string{}, + }, + plugin: &mockDecrypterProvider{ + decrypter: &mockDecrypter{}, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Create a manager with the mock plugin + m := &Manager{ + plugins: map[string]onixPlugin{ + tt.cfg.ID: &mockPlugin{ + symbol: tt.plugin, + }, + }, + closers: []func(){}, + } + + // Call Decryptor + decrypter, err := m.Decryptor(context.Background(), tt.cfg) + + // Check success case + if err != nil { + t.Errorf("unexpected error: %v", err) + } + if decrypter == nil { + t.Error("expected non-nil decrypter, got nil") + } + }) + } +} + +// TestManager_Decryptor_Failure tests the failure scenarios of the Decryptor method +func TestManagerDecryptorFailure(t *testing.T) { + tests := []struct { + name string + cfg *Config + plugin *mockDecrypterProvider + expectedError string + }{ + { + name: "provider error", + cfg: &Config{ + ID: "test-decrypter", + Config: map[string]string{}, + }, + plugin: &mockDecrypterProvider{ + err: errors.New("provider error"), + }, + expectedError: "provider error", + }, + { + name: "plugin not found", + cfg: &Config{ + ID: "nonexistent-decrypter", + Config: map[string]string{}, + }, + plugin: nil, + expectedError: "plugin nonexistent-decrypter not found", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Create a manager with the mock plugin + m := &Manager{ + plugins: make(map[string]onixPlugin), + closers: []func(){}, + } + + // Only add the plugin if it's not nil + if tt.plugin != nil { + m.plugins[tt.cfg.ID] = &mockPlugin{ + symbol: tt.plugin, + } + } + + // Call Decryptor + decrypter, err := m.Decryptor(context.Background(), tt.cfg) + + // Check error + if err == nil { + t.Error("expected error, got nil") + } else if !strings.Contains(err.Error(), tt.expectedError) { + t.Errorf("error = %v, want error containing %q", err, tt.expectedError) + } + if decrypter != nil { + t.Error("expected nil decrypter, got non-nil") + } + }) + } +} + +// TestManager_SignValidator tests the SignValidator method of the Manager +func TestManagerSignValidator(t *testing.T) { + tests := []struct { + name string + cfg *Config + plugin *mockSignValidatorProvider + wantErr bool + }{ + { + name: "successful sign validator creation", + cfg: &Config{ + ID: "test-sign-validator", + Config: map[string]string{}, + }, + plugin: &mockSignValidatorProvider{ + validator: &mockSignValidator{}, + }, + wantErr: true, + }, + { + name: "provider error", + cfg: &Config{ + ID: "test-sign-validator", + Config: map[string]string{}, + }, + plugin: &mockSignValidatorProvider{ + err: errors.New("provider error"), + }, wantErr: true, }, } @@ -271,664 +1346,1174 @@ func TestNewManager(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { ctx := context.Background() - _, cleanup, err := NewManager(ctx, tt.cfg) - if (err != nil) != tt.wantErr { - t.Errorf("NewManager() error = %v, wantErr %v", err, tt.wantErr) - return + m := &Manager{ + plugins: map[string]onixPlugin{ + tt.cfg.ID: &mockPlugin{ + symbol: tt.plugin, + }, + }, + closers: []func(){}, } - if cleanup != nil { - cleanup() + + _, err := m.SignValidator(ctx, tt.cfg) + if (err != nil) != tt.wantErr { + t.Errorf("Manager.SignValidator() error = %v, wantErr %v", err, tt.wantErr) } }) } } -func TestPublisherSuccess(t *testing.T) { - publisherID := "publisherId" - errFunc := func() error { return nil} - mockPublisher := &mockPublisher{} - m := &Manager{ - closers: []func(){}, - plugins: map[string]onixPlugin{ - publisherID: &mockPlugin{ - symbol : &mockPublisherProvider{ - publisher: mockPublisher, - err: errFunc(), - }, - }, - }} - p, err := m.Publisher(context.Background(), &Config{ - ID: publisherID, - Config: map[string]string{}, - }); - if(err != nil) { - t.Errorf("Manager.Publisher() error = %v", err) - } - // if(len(m.closers) == 0) { - // t.Errorf("Manager.Publisher() did not register closer") - // } - if p != mockPublisher { - t.Errorf("Manager.Publisher() did not return the correct publisher") - } -} - -// func TestManager_SchemaValidator(t *testing.T) { -// tests := []struct { -// name string -// cfg *Config -// plugin *mockSchemaValidatorProvider -// wantErr bool -// }{ -// { -// name: "successful validator creation", -// cfg: &Config{ -// ID: "test-validator", -// Config: map[string]string{}, -// }, -// plugin: &mockSchemaValidatorProvider{ -// validator: &mockSchemaValidator{}, -// }, -// wantErr: true, -// }, -// { -// name: "provider error", -// cfg: &Config{ -// ID: "test-validator", -// Config: map[string]string{}, -// }, -// plugin: &mockSchemaValidatorProvider{ -// err: errors.New("provider error"), -// }, -// wantErr: true, -// }, -// } - -// for _, tt := range tests { -// t.Run(tt.name, func(t *testing.T) { -// ctx := context.Background() -// tm := newTestManager() -// tm.mockProviders[tt.cfg.ID] = tt.plugin - -// // Create a mock plugin that returns our provider -// mockPlugin := &plugin.Plugin{} -// tm.plugins[tt.cfg.ID] = mockPlugin - -// _, err := tm.SchemaValidator(ctx, tt.cfg) -// if (err != nil) != tt.wantErr { -// t.Errorf("Manager.SchemaValidator() error = %v, wantErr %v", err, tt.wantErr) -// } -// }) -// } -// } - -// func TestManager_Router(t *testing.T) { -// tests := []struct { -// name string -// cfg *Config -// plugin *mockRouterProvider -// wantErr bool -// }{ -// { -// name: "successful router creation", -// cfg: &Config{ -// ID: "test-router", -// Config: map[string]string{}, -// }, -// plugin: &mockRouterProvider{ -// router: &mockRouter{}, -// }, -// wantErr: true, -// }, -// { -// name: "provider error", -// cfg: &Config{ -// ID: "test-router", -// Config: map[string]string{}, -// }, -// plugin: &mockRouterProvider{ -// err: errors.New("provider error"), -// }, -// wantErr: true, -// }, -// } - -// for _, tt := range tests { -// t.Run(tt.name, func(t *testing.T) { -// ctx := context.Background() -// tm := newTestManager() -// tm.mockProviders[tt.cfg.ID] = tt.plugin - -// _, err := tm.Router(ctx, tt.cfg) -// if (err != nil) != tt.wantErr { -// t.Errorf("Manager.Router() error = %v, wantErr %v", err, tt.wantErr) -// } -// }) -// } -// } - -// func TestManager_Middleware(t *testing.T) { -// tests := []struct { -// name string -// cfg *Config -// plugin *mockMiddlewareProvider -// wantErr bool -// }{ -// { -// name: "successful middleware creation", -// cfg: &Config{ -// ID: "test-middleware", -// Config: map[string]string{}, -// }, -// plugin: &mockMiddlewareProvider{ -// provider: &mockMiddleware{}, -// }, -// wantErr: true, -// }, -// { -// name: "provider error", -// cfg: &Config{ -// ID: "test-middleware", -// Config: map[string]string{}, -// }, -// plugin: &mockMiddlewareProvider{ -// err: errors.New("provider error"), -// }, -// wantErr: true, -// }, -// } - -// for _, tt := range tests { -// t.Run(tt.name, func(t *testing.T) { -// ctx := context.Background() -// tm := newTestManager() -// tm.mockProviders[tt.cfg.ID] = tt.plugin - -// _, err := tm.Middleware(ctx, tt.cfg) -// if (err != nil) != tt.wantErr { -// t.Errorf("Manager.Middleware() error = %v, wantErr %v", err, tt.wantErr) -// } -// }) -// } -// } - -// func TestManager_Step(t *testing.T) { -// tests := []struct { -// name string -// cfg *Config -// plugin *mockStepProvider -// wantErr bool -// }{ -// { -// name: "successful step creation", -// cfg: &Config{ -// ID: "test-step", -// Config: map[string]string{}, -// }, -// plugin: &mockStepProvider{ -// step: &mockStep{}, -// }, -// wantErr: true, -// }, -// { -// name: "provider error", -// cfg: &Config{ -// ID: "test-step", -// Config: map[string]string{}, -// }, -// plugin: &mockStepProvider{ -// err: errors.New("provider error"), -// }, -// wantErr: true, -// }, -// } - -// for _, tt := range tests { -// t.Run(tt.name, func(t *testing.T) { -// ctx := context.Background() -// tm := newTestManager() -// tm.mockProviders[tt.cfg.ID] = tt.plugin - -// _, err := tm.Step(ctx, tt.cfg) -// if (err != nil) != tt.wantErr { -// t.Errorf("Manager.Step() error = %v, wantErr %v", err, tt.wantErr) -// } -// }) -// } -// } - -// func TestManager_Validator(t *testing.T) { -// tests := []struct { -// name string -// cfg *Config -// wantErr bool -// }{ -// { -// name: "unimplemented validator", -// cfg: &Config{ -// ID: "test-validator", -// Config: nil, -// }, -// wantErr: true, -// }, -// } - -// for _, tt := range tests { -// t.Run(tt.name, func(t *testing.T) { -// ctx := context.Background() -// m := &Manager{ -// plugins: make(map[string]*plugin.Plugin), -// closers: []func(){}, -// } - -// // We expect a panic from the unimplemented method -// defer func() { -// if r := recover(); r == nil { -// t.Error("Expected panic from unimplemented Validator method") -// } -// }() - -// _, err := m.Validator(ctx, tt.cfg) -// if (err != nil) != tt.wantErr { -// t.Errorf("Manager.Validator() error = %v, wantErr %v", err, tt.wantErr) -// } -// }) -// } -// } - -// func TestManager_Cache(t *testing.T) { -// tests := []struct { -// name string -// cfg *Config -// plugin *mockCacheProvider -// wantErr bool -// }{ -// { -// name: "successful cache creation", -// cfg: &Config{ -// ID: "test-cache", -// Config: map[string]string{}, -// }, -// plugin: &mockCacheProvider{ -// cache: &mockCache{}, -// }, -// wantErr: true, -// }, -// { -// name: "provider error", -// cfg: &Config{ -// ID: "test-cache", -// Config: map[string]string{}, -// }, -// plugin: &mockCacheProvider{ -// err: errors.New("provider error"), -// }, -// wantErr: true, -// }, -// } - -// for _, tt := range tests { -// t.Run(tt.name, func(t *testing.T) { -// ctx := context.Background() -// tm := newTestManager() -// tm.mockProviders[tt.cfg.ID] = tt.plugin - -// _, err := tm.Cache(ctx, tt.cfg) -// if (err != nil) != tt.wantErr { -// t.Errorf("Manager.Cache() error = %v, wantErr %v", err, tt.wantErr) -// } -// }) -// } -// } - -// func TestManager_Signer(t *testing.T) { -// tests := []struct { -// name string -// cfg *Config -// plugin *mockSignerProvider -// wantErr bool -// }{ -// { -// name: "successful signer creation", -// cfg: &Config{ -// ID: "test-signer", -// Config: map[string]string{}, -// }, -// plugin: &mockSignerProvider{ -// signer: &mockSigner{}, -// }, -// wantErr: true, -// }, -// { -// name: "provider error", -// cfg: &Config{ -// ID: "test-signer", -// Config: map[string]string{}, -// }, -// plugin: &mockSignerProvider{ -// err: errors.New("provider error"), -// }, -// wantErr: true, -// }, -// } - -// for _, tt := range tests { -// t.Run(tt.name, func(t *testing.T) { -// ctx := context.Background() -// tm := newTestManager() -// tm.mockProviders[tt.cfg.ID] = tt.plugin - -// _, err := tm.Signer(ctx, tt.cfg) -// if (err != nil) != tt.wantErr { -// t.Errorf("Manager.Signer() error = %v, wantErr %v", err, tt.wantErr) -// } -// }) -// } -// } - -// func TestManager_Encryptor(t *testing.T) { -// tests := []struct { -// name string -// cfg *Config -// plugin *mockEncrypterProvider -// wantErr bool -// }{ -// { -// name: "successful encrypter creation", -// cfg: &Config{ -// ID: "test-encrypter", -// Config: map[string]string{}, -// }, -// plugin: &mockEncrypterProvider{ -// encrypter: &mockEncrypter{}, -// }, -// wantErr: true, -// }, -// { -// name: "provider error", -// cfg: &Config{ -// ID: "test-encrypter", -// Config: map[string]string{}, -// }, -// plugin: &mockEncrypterProvider{ -// err: errors.New("provider error"), -// }, -// wantErr: true, -// }, -// } - -// for _, tt := range tests { -// t.Run(tt.name, func(t *testing.T) { -// ctx := context.Background() -// tm := newTestManager() -// tm.mockProviders[tt.cfg.ID] = tt.plugin - -// _, err := tm.Encryptor(ctx, tt.cfg) -// if (err != nil) != tt.wantErr { -// t.Errorf("Manager.Encryptor() error = %v, wantErr %v", err, tt.wantErr) -// } -// }) -// } -// } - -// func TestManager_Decryptor(t *testing.T) { -// tests := []struct { -// name string -// cfg *Config -// plugin *mockDecrypterProvider -// wantErr bool -// }{ -// { -// name: "successful decrypter creation", -// cfg: &Config{ -// ID: "test-decrypter", -// Config: map[string]string{}, -// }, -// plugin: &mockDecrypterProvider{ -// decrypter: &mockDecrypter{}, -// }, -// wantErr: true, -// }, -// { -// name: "provider error", -// cfg: &Config{ -// ID: "test-decrypter", -// Config: map[string]string{}, -// }, -// plugin: &mockDecrypterProvider{ -// err: errors.New("provider error"), -// }, -// wantErr: true, -// }, -// } - -// for _, tt := range tests { -// t.Run(tt.name, func(t *testing.T) { -// ctx := context.Background() -// tm := newTestManager() -// tm.mockProviders[tt.cfg.ID] = tt.plugin - -// _, err := tm.Decryptor(ctx, tt.cfg) -// if (err != nil) != tt.wantErr { -// t.Errorf("Manager.Decryptor() error = %v, wantErr %v", err, tt.wantErr) -// } -// }) -// } -// } - -// func TestManager_SignValidator(t *testing.T) { -// tests := []struct { -// name string -// cfg *Config -// plugin *mockSignValidatorProvider -// wantErr bool -// }{ -// { -// name: "successful sign validator creation", -// cfg: &Config{ -// ID: "test-sign-validator", -// Config: map[string]string{}, -// }, -// plugin: &mockSignValidatorProvider{ -// validator: &mockSignValidator{}, -// }, -// wantErr: true, -// }, -// { -// name: "provider error", -// cfg: &Config{ -// ID: "test-sign-validator", -// Config: map[string]string{}, -// }, -// plugin: &mockSignValidatorProvider{ -// err: errors.New("provider error"), -// }, -// wantErr: true, -// }, -// } - -// for _, tt := range tests { -// t.Run(tt.name, func(t *testing.T) { -// ctx := context.Background() -// tm := newTestManager() -// tm.mockProviders[tt.cfg.ID] = tt.plugin - -// _, err := tm.SignValidator(ctx, tt.cfg) -// if (err != nil) != tt.wantErr { -// t.Errorf("Manager.SignValidator() error = %v, wantErr %v", err, tt.wantErr) -// } -// }) -// } -// } - -// func TestManager_KeyManager(t *testing.T) { -// tests := []struct { -// name string -// cfg *Config -// plugin *mockKeyManagerProvider -// wantErr bool -// }{ -// { -// name: "successful key manager creation", -// cfg: &Config{ -// ID: "test-key-manager", -// Config: map[string]string{}, -// }, -// plugin: &mockKeyManagerProvider{ -// manager: &mockKeyManager{}, -// }, -// wantErr: true, -// }, -// { -// name: "provider error", -// cfg: &Config{ -// ID: "test-key-manager", -// Config: map[string]string{}, -// }, -// plugin: &mockKeyManagerProvider{ -// err: errors.New("provider error"), -// }, -// wantErr: true, -// }, -// } - -// for _, tt := range tests { -// t.Run(tt.name, func(t *testing.T) { -// ctx := context.Background() -// tm := newTestManager() -// tm.mockProviders[tt.cfg.ID] = tt.plugin - -// // Create mock cache and registry lookup -// mockCache := &mockCache{} -// mockRegistry := &mockRegistryLookup{} - -// _, err := tm.KeyManager(ctx, mockCache, mockRegistry, tt.cfg) -// if (err != nil) != tt.wantErr { -// t.Errorf("Manager.KeyManager() error = %v, wantErr %v", err, tt.wantErr) -// } -// }) -// } -// } - -func TestUnzip(t *testing.T) { +// TestManager_KeyManager_Success tests the successful scenarios of the KeyManager method +func TestManagerKeyManagerSuccess(t *testing.T) { tests := []struct { - name string - src string - dest string - wantErr bool - setup func() (string, string, func()) + name string + cfg *Config + plugin *mockKeyManagerProvider }{ { - name: "successful unzip", - setup: func() (string, string, func()) { - // Create a temporary directory for the test - tmpDir, err := os.MkdirTemp("", "unzip-test") - if err != nil { - t.Fatalf("failed to create temp dir: %v", err) - } - - // Create a temporary zip file - zipFile := filepath.Join(tmpDir, "test.zip") - f, err := os.Create(zipFile) - if err != nil { - t.Fatalf("failed to create zip file: %v", err) - } - defer f.Close() - - // Create a zip writer - zipWriter := zip.NewWriter(f) - defer zipWriter.Close() - - // Add a file to the zip - fileWriter, err := zipWriter.Create("test.txt") - if err != nil { - t.Fatalf("failed to create file in zip: %v", err) - } - _, err = fileWriter.Write([]byte("test content")) - if err != nil { - t.Fatalf("failed to write to zip file: %v", err) - } - - // Create a destination directory - destDir := filepath.Join(tmpDir, "dest") - if err := os.MkdirAll(destDir, 0755); err != nil { - t.Fatalf("failed to create dest dir: %v", err) - } - - return zipFile, destDir, func() { - os.RemoveAll(tmpDir) - } + name: "successful key manager creation", + cfg: &Config{ + ID: "test-key-manager", + Config: map[string]string{}, }, - wantErr: false, - }, - { - name: "nonexistent source file", - setup: func() (string, string, func()) { - tmpDir, err := os.MkdirTemp("", "unzip-test") - if err != nil { - t.Fatalf("failed to create temp dir: %v", err) - } - destDir := filepath.Join(tmpDir, "dest") - if err := os.MkdirAll(destDir, 0755); err != nil { - t.Fatalf("failed to create dest dir: %v", err) - } - return "nonexistent.zip", destDir, func() { - os.RemoveAll(tmpDir) - } + plugin: &mockKeyManagerProvider{ + keyManager: &mockKeyManager{}, }, - wantErr: true, - }, - { - name: "invalid zip file", - setup: func() (string, string, func()) { - tmpDir, err := os.MkdirTemp("", "unzip-test") - if err != nil { - t.Fatalf("failed to create temp dir: %v", err) - } - - // Create an invalid zip file - zipFile := filepath.Join(tmpDir, "test.zip") - f, err := os.Create(zipFile) - if err != nil { - t.Fatalf("failed to create zip file: %v", err) - } - defer f.Close() - - // Write invalid content - _, err = f.Write([]byte("invalid zip content")) - if err != nil { - t.Fatalf("failed to write to zip file: %v", err) - } - - // Create a destination directory - destDir := filepath.Join(tmpDir, "dest") - if err := os.MkdirAll(destDir, 0755); err != nil { - t.Fatalf("failed to create dest dir: %v", err) - } - - return zipFile, destDir, func() { - os.RemoveAll(tmpDir) - } - }, - wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - src, dest, cleanup := tt.setup() - defer cleanup() - - err := unzip(src, dest) - if (err != nil) != tt.wantErr { - t.Errorf("unzip() error = %v, wantErr %v", err, tt.wantErr) + // Create a manager with the mock plugin + m := &Manager{ + plugins: map[string]onixPlugin{ + tt.cfg.ID: &mockPlugin{ + symbol: tt.plugin, + }, + }, + closers: []func(){}, } - if !tt.wantErr { - // Verify that the file was extracted - extractedFile := filepath.Join(dest, "test.txt") - if _, err := os.Stat(extractedFile); os.IsNotExist(err) { - t.Errorf("unzip() did not extract file to %s", extractedFile) - } + // Create mock cache and registry lookup + mockCache := &mockCache{} + mockRegistry := &mockRegistryLookup{} + + // Call KeyManager + keyManager, err := m.KeyManager(context.Background(), mockCache, mockRegistry, tt.cfg) + + // Check success case + if err != nil { + t.Errorf("unexpected error: %v", err) + } + if keyManager == nil { + t.Error("expected non-nil key manager, got nil") + } + }) + } +} + +// TestManager_KeyManager_Failure tests the failure scenarios of the KeyManager method +func TestManagerKeyManagerFailure(t *testing.T) { + tests := []struct { + name string + cfg *Config + plugin *mockKeyManagerProvider + expectedError string + }{ + { + name: "provider error", + cfg: &Config{ + ID: "test-key-manager", + Config: map[string]string{}, + }, + plugin: &mockKeyManagerProvider{ + err: errors.New("provider error"), + }, + expectedError: "provider error", + }, + { + name: "plugin not found", + cfg: &Config{ + ID: "nonexistent-key-manager", + Config: map[string]string{}, + }, + plugin: nil, + expectedError: "plugin nonexistent-key-manager not found", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Create a manager with the mock plugin + m := &Manager{ + plugins: make(map[string]onixPlugin), + closers: []func(){}, + } + + // Only add the plugin if it's not nil + if tt.plugin != nil { + m.plugins[tt.cfg.ID] = &mockPlugin{ + symbol: tt.plugin, + } + } + + // Create mock cache and registry lookup + mockCache := &mockCache{} + mockRegistry := &mockRegistryLookup{} + + // Call KeyManager + keyManager, err := m.KeyManager(context.Background(), mockCache, mockRegistry, tt.cfg) + + // Check error + if err == nil { + t.Error("expected error, got nil") + } else if !strings.Contains(err.Error(), tt.expectedError) { + t.Errorf("error = %v, want error containing %q", err, tt.expectedError) + } + if keyManager != nil { + t.Error("expected nil key manager, got non-nil") + } + }) + } +} + +// TestUnzip_Success tests the successful scenarios of the unzip function +func TestUnzipSuccess(t *testing.T) { + tests := []struct { + name string + setupFunc func() (string, string, func()) // returns src, dest, cleanup + verifyFunc func(t *testing.T, dest string) + }{ + { + name: "extract single file", + setupFunc: func() (string, string, func()) { + // Create a temporary directory for the test + tempDir, err := os.MkdirTemp("", "unzip-test-*") + if err != nil { + t.Fatalf("Failed to create temp dir: %v", err) + } + + // Create a zip file with a single test file + zipPath := filepath.Join(tempDir, "test.zip") + zipFile, err := os.Create(zipPath) + if err != nil { + t.Fatalf("Failed to create zip file: %v", err) + } + + zipWriter := zip.NewWriter(zipFile) + defer zipWriter.Close() + + // Add a test file to the zip + testFile, err := zipWriter.Create("test.txt") + if err != nil { + t.Fatalf("Failed to create file in zip: %v", err) + } + testFile.Write([]byte("test content")) + + zipWriter.Close() + zipFile.Close() + + // Create destination directory + destDir := filepath.Join(tempDir, "extracted") + return zipPath, destDir, func() { + os.RemoveAll(tempDir) + } + }, + verifyFunc: func(t *testing.T, dest string) { + // Verify the extracted file exists and has correct content + content, err := os.ReadFile(filepath.Join(dest, "test.txt")) + if err != nil { + t.Errorf("Failed to read extracted file: %v", err) + } + if string(content) != "test content" { + t.Errorf("Extracted file content = %v, want %v", string(content), "test content") + } + }, + }, + { + name: "extract file in subdirectory", + setupFunc: func() (string, string, func()) { + // Create a temporary directory for the test + tempDir, err := os.MkdirTemp("", "unzip-test-*") + if err != nil { + t.Fatalf("Failed to create temp dir: %v", err) + } + + // Create a zip file with a file in a subdirectory + zipPath := filepath.Join(tempDir, "test.zip") + zipFile, err := os.Create(zipPath) + if err != nil { + t.Fatalf("Failed to create zip file: %v", err) + } + + zipWriter := zip.NewWriter(zipFile) + defer zipWriter.Close() + + // Add a file in a subdirectory + testFile, err := zipWriter.Create("subdir/test.txt") + if err != nil { + t.Fatalf("Failed to create file in zip: %v", err) + } + testFile.Write([]byte("subdirectory content")) + + zipWriter.Close() + zipFile.Close() + + // Create destination directory + destDir := filepath.Join(tempDir, "extracted") + return zipPath, destDir, func() { + os.RemoveAll(tempDir) + } + }, + verifyFunc: func(t *testing.T, dest string) { + // Verify the extracted file in subdirectory exists and has correct content + content, err := os.ReadFile(filepath.Join(dest, "subdir/test.txt")) + if err != nil { + t.Errorf("Failed to read extracted file in subdirectory: %v", err) + } + if string(content) != "subdirectory content" { + t.Errorf("Extracted file content in subdirectory = %v, want %v", string(content), "subdirectory content") + } + }, + }, + { + name: "extract multiple files", + setupFunc: func() (string, string, func()) { + // Create a temporary directory for the test + tempDir, err := os.MkdirTemp("", "unzip-test-*") + if err != nil { + t.Fatalf("Failed to create temp dir: %v", err) + } + + // Create a zip file with multiple files + zipPath := filepath.Join(tempDir, "test.zip") + zipFile, err := os.Create(zipPath) + if err != nil { + t.Fatalf("Failed to create zip file: %v", err) + } + + zipWriter := zip.NewWriter(zipFile) + defer zipWriter.Close() + + // Add multiple files to the zip + files := map[string]string{ + "file1.txt": "content of file 1", + "file2.txt": "content of file 2", + "subdir/file3.txt": "content of file 3", + } + + for name, content := range files { + testFile, err := zipWriter.Create(name) + if err != nil { + t.Fatalf("Failed to create file in zip: %v", err) + } + testFile.Write([]byte(content)) + } + + zipWriter.Close() + zipFile.Close() + + // Create destination directory + destDir := filepath.Join(tempDir, "extracted") + return zipPath, destDir, func() { + os.RemoveAll(tempDir) + } + }, + verifyFunc: func(t *testing.T, dest string) { + // Verify all extracted files exist and have correct content + expectedFiles := map[string]string{ + "file1.txt": "content of file 1", + "file2.txt": "content of file 2", + "subdir/file3.txt": "content of file 3", + } + + for path, expectedContent := range expectedFiles { + content, err := os.ReadFile(filepath.Join(dest, path)) + if err != nil { + t.Errorf("Failed to read extracted file %s: %v", path, err) + } + if string(content) != expectedContent { + t.Errorf("Extracted file %s content = %v, want %v", path, string(content), expectedContent) + } + } + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Setup test environment + src, dest, cleanup := tt.setupFunc() + defer cleanup() + + // Run the test + err := unzip(src, dest) + if err != nil { + t.Errorf("unzip() error = %v, want nil", err) + } + + // Verify the result + tt.verifyFunc(t, dest) + }) + } +} + +// TestUnzip_Failure tests the failure scenarios of the unzip function +func TestUnzipFailure(t *testing.T) { + tests := []struct { + name string + setupFunc func() (string, string, func()) // returns src, dest, cleanup + expectedError string + }{ + { + name: "nonexistent source file", + setupFunc: func() (string, string, func()) { + tempDir, err := os.MkdirTemp("", "unzip-test-*") + if err != nil { + t.Fatalf("Failed to create temp dir: %v", err) + } + return "nonexistent.zip", filepath.Join(tempDir, "extracted"), func() { + os.RemoveAll(tempDir) + } + }, + expectedError: "open nonexistent.zip: no such file or directory", + }, + { + name: "invalid zip file", + setupFunc: func() (string, string, func()) { + tempDir, err := os.MkdirTemp("", "unzip-test-*") + if err != nil { + t.Fatalf("Failed to create temp dir: %v", err) + } + + // Create an invalid zip file + zipPath := filepath.Join(tempDir, "invalid.zip") + if err := os.WriteFile(zipPath, []byte("not a zip file"), 0644); err != nil { + t.Fatalf("Failed to create invalid zip file: %v", err) + } + + return zipPath, filepath.Join(tempDir, "extracted"), func() { + os.RemoveAll(tempDir) + } + }, + expectedError: "zip: not a valid zip file", + }, + { + name: "destination directory creation failure", + setupFunc: func() (string, string, func()) { + tempDir, err := os.MkdirTemp("", "unzip-test-*") + if err != nil { + t.Fatalf("Failed to create temp dir: %v", err) + } + + // Create a valid zip file + zipPath := filepath.Join(tempDir, "test.zip") + zipFile, err := os.Create(zipPath) + if err != nil { + t.Fatalf("Failed to create zip file: %v", err) + } + + zipWriter := zip.NewWriter(zipFile) + defer zipWriter.Close() + + testFile, err := zipWriter.Create("test.txt") + if err != nil { + t.Fatalf("Failed to create file in zip: %v", err) + } + testFile.Write([]byte("test content")) + + zipWriter.Close() + zipFile.Close() + + // Create a file instead of a directory to cause the error + destPath := filepath.Join(tempDir, "extracted") + if err := os.WriteFile(destPath, []byte("not a directory"), 0644); err != nil { + t.Fatalf("Failed to create file at destination: %v", err) + } + + return zipPath, destPath, func() { + os.RemoveAll(tempDir) + } + }, + expectedError: "mkdir", + }, + { + name: "file creation failure", + setupFunc: func() (string, string, func()) { + tempDir, err := os.MkdirTemp("", "unzip-test-*") + if err != nil { + t.Fatalf("Failed to create temp dir: %v", err) + } + + // Create a zip file with a file that would be extracted to a read-only location + zipPath := filepath.Join(tempDir, "test.zip") + zipFile, err := os.Create(zipPath) + if err != nil { + t.Fatalf("Failed to create zip file: %v", err) + } + + zipWriter := zip.NewWriter(zipFile) + defer zipWriter.Close() + + testFile, err := zipWriter.Create("test.txt") + if err != nil { + t.Fatalf("Failed to create file in zip: %v", err) + } + testFile.Write([]byte("test content")) + + zipWriter.Close() + zipFile.Close() + + // Create a read-only directory + destDir := filepath.Join(tempDir, "extracted") + if err := os.MkdirAll(destDir, 0555); err != nil { + t.Fatalf("Failed to create read-only directory: %v", err) + } + + return zipPath, destDir, func() { + os.RemoveAll(tempDir) + } + }, + expectedError: "permission denied", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Setup test environment + src, dest, cleanup := tt.setupFunc() + defer cleanup() + + // Run the test + err := unzip(src, dest) + if err == nil { + t.Errorf("unzip() error = nil, want error containing %q", tt.expectedError) + } else if !strings.Contains(err.Error(), tt.expectedError) { + t.Errorf("unzip() error = %v, want error containing %q", err, tt.expectedError) + } + }) + } +} + +// TestManager_CloserCleanup tests the cleanup functionality of closer functions +func TestManagerCloserCleanup(t *testing.T) { + // Create a manager + m := &Manager{ + closers: make([]func(), 0), + } + + // Track if closers were called + closer1Called := false + closer2Called := false + closer3Called := false + + // Add closers using the same pattern as in manager.go + m.closers = append(m.closers, func() { + if err := func() error { + closer1Called = true + return nil + }(); err != nil { + panic(err) + } + }) + + m.closers = append(m.closers, func() { + if err := func() error { + closer2Called = true + return nil + }(); err != nil { + panic(err) + } + }) + + m.closers = append(m.closers, func() { + if err := func() error { + closer3Called = true + return nil + }(); err != nil { + panic(err) + } + }) + + // Verify closers were added + if len(m.closers) != 3 { + t.Errorf("Expected 3 closers, got %d", len(m.closers)) + } + + // Execute all closers + for _, closer := range m.closers { + closer() + } + + // Verify all closers were called + if !closer1Called { + t.Errorf("Closer 1 was not called") + } + if !closer2Called { + t.Errorf("Closer 2 was not called") + } + if !closer3Called { + t.Errorf("Closer 3 was not called") + } +} + +// TestManager_CloserManagement_Success tests the successful scenarios of closer management +func TestManagerCloserManagementSuccess(t *testing.T) { + tests := []struct { + name string + initialClosers []func() + newCloser func() error + expectedCount int + verifyExecution bool + }{ + { + name: "add first closer to empty list", + initialClosers: []func(){}, + newCloser: func() error { return nil }, + expectedCount: 1, + verifyExecution: true, + }, + { + name: "add closer to existing list", + initialClosers: []func(){func() {}}, + newCloser: func() error { return nil }, + expectedCount: 2, + verifyExecution: true, + }, + { + name: "ignore nil closer", + initialClosers: []func(){func() {}}, + newCloser: nil, + expectedCount: 1, + verifyExecution: false, + }, + { + name: "add multiple closers sequentially", + initialClosers: []func(){func() {}, func() {}}, + newCloser: func() error { return nil }, + expectedCount: 3, + verifyExecution: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Create a manager with initial closers + m := &Manager{ + closers: make([]func(), 0, len(tt.initialClosers)), + } + m.closers = append(m.closers, tt.initialClosers...) + + // Track if the new closer was called + closerCalled := false + + // Add the new closer if it's not nil + if tt.newCloser != nil { + m.closers = append(m.closers, func() { + if err := func() error { + closerCalled = true + return tt.newCloser() + }(); err != nil { + panic(err) + } + }) + } + + // Verify the number of closers + if len(m.closers) != tt.expectedCount { + t.Errorf("got %d closers, want %d", len(m.closers), tt.expectedCount) + } + + // Execute all closers + for _, closer := range m.closers { + closer() + } + + // Verify the new closer was called if expected + if tt.verifyExecution && !closerCalled { + t.Error("new closer was not called") + } + }) + } +} + +// TestManager_CloserManagement_Failure tests the failure scenarios of closer management +func TestManagerCloserManagementFailure(t *testing.T) { + tests := []struct { + name string + newCloser func() error + expectedError string + }{ + { + name: "closer returns error", + newCloser: func() error { + return fmt.Errorf("intentional error") + }, + expectedError: "intentional error", + }, + { + name: "closer panics with string", + newCloser: func() error { + panic("intentional panic") + }, + expectedError: "intentional panic", + }, + { + name: "closer panics with error", + newCloser: func() error { + panic(fmt.Errorf("panic error")) + }, + expectedError: "panic error", + }, + { + name: "closer panics with nil", + newCloser: func() error { + panic(nil) + }, + expectedError: "panic called with nil argument", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Create a manager + m := &Manager{ + closers: make([]func(), 0), + } + + // Add the closer that will fail + m.closers = append(m.closers, func() { + if err := tt.newCloser(); err != nil { + panic(err) + } + }) + + // Execute the closer and verify it panics + defer func() { + r := recover() + if r == nil { + t.Error("expected panic but got none") + return + } + + // Convert panic value to string for comparison + var errStr string + switch v := r.(type) { + case error: + errStr = v.Error() + case string: + errStr = v + default: + errStr = "panic called with nil argument" + } + + if errStr != tt.expectedError { + t.Errorf("got panic %q, want %q", errStr, tt.expectedError) + } + }() + + // This should panic + m.closers[0]() + }) + } +} + +// TestValidateMgrCfgSuccess tests the successful scenarios of the validateMgrCfg function +func TestValidateMgrCfgSuccess(t *testing.T) { + tests := []struct { + name string + cfg *ManagerConfig + }{ + { + name: "valid config with empty fields", + cfg: &ManagerConfig{ + Root: "", + RemoteRoot: "", + }, + }, + { + name: "valid config with root path", + cfg: &ManagerConfig{ + Root: "/path/to/plugins", + RemoteRoot: "", + }, + }, + { + name: "valid config with remote root", + cfg: &ManagerConfig{ + Root: "/path/to/plugins", + RemoteRoot: "/path/to/remote/plugins.zip", + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := validateMgrCfg(tt.cfg) + if err != nil { + t.Errorf("validateMgrCfg() error = %v, want nil", err) + } + }) + } +} + +func TestLoadPluginSuccess(t *testing.T) { + tests := []struct { + name string + setupFunc func() (string, string, func()) // returns path, id, cleanup + }{ + { + name: "load valid plugin", + setupFunc: func() (string, string, func()) { + // Create a temporary directory for the test + tempDir, err := os.MkdirTemp("", "plugin-test-*") + if err != nil { + t.Fatalf("Failed to create temp dir: %v", err) + } + + // Create a mock plugin file (we can't create a real .so file in tests) + pluginPath := filepath.Join(tempDir, "test-plugin.so") + if err := os.WriteFile(pluginPath, []byte("mock plugin content"), 0644); err != nil { + t.Fatalf("Failed to create mock plugin file: %v", err) + } + + return pluginPath, "test-plugin", func() { + os.RemoveAll(tempDir) + } + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Skip the test since we can't create real .so files in tests + t.Skip("Cannot create real .so files in tests") + + // Setup test environment + path, id, cleanup := tt.setupFunc() + defer cleanup() + + // Run the test + p, elapsed, err := loadPlugin(context.Background(), path, id) + if err != nil { + t.Errorf("loadPlugin() error = %v, want nil", err) + } + if p == nil { + t.Error("loadPlugin() returned nil plugin") + } + if elapsed == 0 { + t.Error("loadPlugin() returned zero elapsed time") + } + }) + } +} + +// TestLoadPluginFailure tests the failure scenarios of the loadPlugin function +func TestLoadPluginFailure(t *testing.T) { + tests := []struct { + name string + setupFunc func() (string, string, func()) // returns path, id, cleanup + expectedError string + }{ + { + name: "nonexistent plugin file", + setupFunc: func() (string, string, func()) { + tempDir, err := os.MkdirTemp("", "plugin-test-*") + if err != nil { + t.Fatalf("Failed to create temp dir: %v", err) + } + return filepath.Join(tempDir, "nonexistent.so"), "nonexistent", func() { + os.RemoveAll(tempDir) + } + }, + expectedError: "failed to open plugin nonexistent: plugin.Open", + }, + { + name: "invalid plugin file", + setupFunc: func() (string, string, func()) { + tempDir, err := os.MkdirTemp("", "plugin-test-*") + if err != nil { + t.Fatalf("Failed to create temp dir: %v", err) + } + + // Create an invalid plugin file + pluginPath := filepath.Join(tempDir, "invalid.so") + if err := os.WriteFile(pluginPath, []byte("not a valid plugin"), 0644); err != nil { + t.Fatalf("Failed to create invalid plugin file: %v", err) + } + + return pluginPath, "invalid", func() { + os.RemoveAll(tempDir) + } + }, + expectedError: "failed to open plugin invalid: plugin.Open", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Setup test environment + path, id, cleanup := tt.setupFunc() + defer cleanup() + + // Run the test + p, elapsed, err := loadPlugin(context.Background(), path, id) + if err == nil { + t.Errorf("loadPlugin() error = nil, want error containing %q", tt.expectedError) + } else if !strings.Contains(err.Error(), tt.expectedError) { + t.Errorf("loadPlugin() error = %v, want error containing %q", err, tt.expectedError) + } + if p != nil { + t.Error("loadPlugin() returned non-nil plugin for error case") + } + if elapsed != 0 { + t.Error("loadPlugin() returned non-zero elapsed time for error case") + } + }) + } +} + +// TestPluginsSuccess tests the successful scenarios of the plugins function +func TestPluginsSuccess(t *testing.T) { + tests := []struct { + name string + setupFunc func() (*ManagerConfig, func()) // returns config and cleanup + wantCount int + }{ + { + name: "empty directory", + setupFunc: func() (*ManagerConfig, func()) { + // Create a temporary directory for the test + tempDir, err := os.MkdirTemp("", "plugins-test-*") + if err != nil { + t.Fatalf("Failed to create temp dir: %v", err) + } + + cfg := &ManagerConfig{ + Root: tempDir, + RemoteRoot: "", + } + + return cfg, func() { + os.RemoveAll(tempDir) + } + }, + wantCount: 0, + }, + { + name: "directory with non-plugin files", + setupFunc: func() (*ManagerConfig, func()) { + // Create a temporary directory for the test + tempDir, err := os.MkdirTemp("", "plugins-test-*") + if err != nil { + t.Fatalf("Failed to create temp dir: %v", err) + } + + // Create some non-plugin files + files := []string{ + "file1.txt", + "file2.json", + "file3.go", + } + for _, file := range files { + if err := os.WriteFile(filepath.Join(tempDir, file), []byte("test content"), 0644); err != nil { + t.Fatalf("Failed to create test file: %v", err) + } + } + + cfg := &ManagerConfig{ + Root: tempDir, + RemoteRoot: "", + } + + return cfg, func() { + os.RemoveAll(tempDir) + } + }, + wantCount: 0, + }, + { + name: "directory with subdirectories", + setupFunc: func() (*ManagerConfig, func()) { + // Create a temporary directory for the test + tempDir, err := os.MkdirTemp("", "plugins-test-*") + if err != nil { + t.Fatalf("Failed to create temp dir: %v", err) + } + + // Create some subdirectories + dirs := []string{ + "dir1", + "dir2/subdir", + } + for _, dir := range dirs { + if err := os.MkdirAll(filepath.Join(tempDir, dir), 0755); err != nil { + t.Fatalf("Failed to create directory: %v", err) + } + } + + cfg := &ManagerConfig{ + Root: tempDir, + RemoteRoot: "", + } + + return cfg, func() { + os.RemoveAll(tempDir) + } + }, + wantCount: 0, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Setup test environment + cfg, cleanup := tt.setupFunc() + defer cleanup() + + // Run the test + got, err := plugins(context.Background(), cfg) + if err != nil { + t.Errorf("plugins() error = %v, want nil", err) + } + if len(got) != tt.wantCount { + t.Errorf("plugins() returned %d plugins, want %d", len(got), tt.wantCount) + } + }) + } +} + +// TestPluginsFailure tests the failure scenarios of the plugins function +func TestPluginsFailure(t *testing.T) { + tests := []struct { + name string + setupFunc func() (*ManagerConfig, func()) // returns config and cleanup + expectedError string + }{ + { + name: "nonexistent directory", + setupFunc: func() (*ManagerConfig, func()) { + tempDir, err := os.MkdirTemp("", "plugins-test-*") + if err != nil { + t.Fatalf("Failed to create temp dir: %v", err) + } + os.RemoveAll(tempDir) // Remove the directory to cause an error + + cfg := &ManagerConfig{ + Root: tempDir, + RemoteRoot: "", + } + + return cfg, func() {} + }, + expectedError: "no such file or directory", + }, + { + name: "permission denied", + setupFunc: func() (*ManagerConfig, func()) { + // Create a temporary directory for the test + tempDir, err := os.MkdirTemp("", "plugins-test-*") + if err != nil { + t.Fatalf("Failed to create temp dir: %v", err) + } + + // Remove read permission from the directory + if err := os.Chmod(tempDir, 0); err != nil { + t.Fatalf("Failed to change directory permissions: %v", err) + } + + cfg := &ManagerConfig{ + Root: tempDir, + RemoteRoot: "", + } + + return cfg, func() { + os.Chmod(tempDir, 0755) // Restore permissions before cleanup + os.RemoveAll(tempDir) + } + }, + expectedError: "permission denied", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Setup test environment + cfg, cleanup := tt.setupFunc() + defer cleanup() + + // Run the test + got, err := plugins(context.Background(), cfg) + if err == nil { + t.Errorf("plugins() error = nil, want error containing %q", tt.expectedError) + } else if !strings.Contains(err.Error(), tt.expectedError) { + t.Errorf("plugins() error = %v, want error containing %q", err, tt.expectedError) + } + if got != nil { + t.Error("plugins() returned non-nil map for error case") + } + }) + } +} + +// TestProviderSuccess tests the successful scenarios of the provider function +func TestProviderSuccess(t *testing.T) { + tests := []struct { + name string + plugins map[string]onixPlugin + id string + wantType interface{} + }{ + { + name: "get publisher provider", + plugins: map[string]onixPlugin{ + "test-plugin": &mockPlugin{ + symbol: &mockPublisherProvider{ + publisher: &mockPublisher{}, + }, + err: nil, + }, + }, + id: "test-plugin", + wantType: (*definition.PublisherProvider)(nil), + }, + { + name: "get schema validator provider", + plugins: map[string]onixPlugin{ + "test-plugin": &mockPlugin{ + symbol: &mockSchemaValidatorProvider{ + validator: &mockSchemaValidator{}, + }, + err: nil, + }, + }, + id: "test-plugin", + wantType: (*definition.SchemaValidatorProvider)(nil), + }, + { + name: "get router provider", + plugins: map[string]onixPlugin{ + "test-plugin": &mockPlugin{ + symbol: &mockRouterProvider{ + router: &mockRouter{}, + }, + err: nil, + }, + }, + id: "test-plugin", + wantType: (*definition.RouterProvider)(nil), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Run the test + switch tt.wantType.(type) { + case *definition.PublisherProvider: + got, err := provider[definition.PublisherProvider](tt.plugins, tt.id) + if err != nil { + t.Errorf("provider() error = %v, want nil", err) + } + if got == nil { + t.Error("provider() returned nil provider") + } + case *definition.SchemaValidatorProvider: + got, err := provider[definition.SchemaValidatorProvider](tt.plugins, tt.id) + if err != nil { + t.Errorf("provider() error = %v, want nil", err) + } + if got == nil { + t.Error("provider() returned nil provider") + } + case *definition.RouterProvider: + got, err := provider[definition.RouterProvider](tt.plugins, tt.id) + if err != nil { + t.Errorf("provider() error = %v, want nil", err) + } + if got == nil { + t.Error("provider() returned nil provider") + } + default: + t.Errorf("unsupported provider type: %T", tt.wantType) + } + }) + } +} + +// TestProviderFailure tests the failure scenarios of the provider function +func TestProviderFailure(t *testing.T) { + tests := []struct { + name string + plugins map[string]onixPlugin + id string + wantErrMsg string + }{ + { + name: "plugin not found", + plugins: map[string]onixPlugin{}, + id: "nonexistent", + wantErrMsg: "plugin nonexistent not found", + }, + { + name: "lookup error", + plugins: map[string]onixPlugin{ + "test-plugin": &mockPlugin{ + symbol: nil, + err: errors.New("lookup failed"), + }, + }, + id: "test-plugin", + wantErrMsg: "lookup failed", + }, + { + name: "invalid provider type", + plugins: map[string]onixPlugin{ + "test-plugin": &mockPlugin{ + symbol: &struct{}{}, // Invalid type + err: nil, + }, + }, + id: "test-plugin", + wantErrMsg: "failed to cast Provider for test-plugin", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Test with PublisherProvider type + got, err := provider[definition.PublisherProvider](tt.plugins, tt.id) + if err == nil { + t.Error("provider() expected error, got nil") + } + if !strings.Contains(err.Error(), tt.wantErrMsg) { + t.Errorf("provider() error = %v, want error containing %v", err, tt.wantErrMsg) + } + if got != nil { + t.Error("provider() expected nil provider") + } + + // Test with SchemaValidatorProvider type + gotValidator, err := provider[definition.SchemaValidatorProvider](tt.plugins, tt.id) + if err == nil { + t.Error("provider() expected error, got nil") + } + if !strings.Contains(err.Error(), tt.wantErrMsg) { + t.Errorf("provider() error = %v, want error containing %v", err, tt.wantErrMsg) + } + if gotValidator != nil { + t.Error("provider() expected nil provider") + } + + // Test with RouterProvider type + gotRouter, err := provider[definition.RouterProvider](tt.plugins, tt.id) + if err == nil { + t.Error("provider() expected error, got nil") + } + if !strings.Contains(err.Error(), tt.wantErrMsg) { + t.Errorf("provider() error = %v, want error containing %v", err, tt.wantErrMsg) + } + if gotRouter != nil { + t.Error("provider() expected nil provider") } }) }