From 086afefc75fb22e4ac6d96b07f94bb5420998b7f Mon Sep 17 00:00:00 2001 From: Marc Nuri Date: Fri, 10 Oct 2025 15:07:37 +0200 Subject: [PATCH] test(kubernetes): provider registry tests (#371) Required tests prior to refactoring Provider and Manager Signed-off-by: Marc Nuri --- pkg/kubernetes/provider_registry_test.go | 56 ++++++++++ pkg/kubernetes/provider_test.go | 127 +++++++++++++++++++++++ 2 files changed, 183 insertions(+) create mode 100644 pkg/kubernetes/provider_registry_test.go create mode 100644 pkg/kubernetes/provider_test.go diff --git a/pkg/kubernetes/provider_registry_test.go b/pkg/kubernetes/provider_registry_test.go new file mode 100644 index 0000000..e52fbdf --- /dev/null +++ b/pkg/kubernetes/provider_registry_test.go @@ -0,0 +1,56 @@ +package kubernetes + +import ( + "testing" + + "github.com/containers/kubernetes-mcp-server/pkg/config" + "github.com/stretchr/testify/suite" +) + +type ProviderRegistryTestSuite struct { + BaseProviderSuite +} + +func (s *ProviderRegistryTestSuite) TestRegisterProvider() { + s.Run("With no pre-existing provider, registers the provider", func() { + RegisterProvider("test-strategy", func(m *Manager, cfg *config.StaticConfig) (ManagerProvider, error) { + return nil, nil + }) + _, exists := providerFactories["test-strategy"] + s.True(exists, "Provider should be registered") + }) + s.Run("With pre-existing provider, panics", func() { + RegisterProvider("test-pre-existent", func(m *Manager, cfg *config.StaticConfig) (ManagerProvider, error) { + return nil, nil + }) + s.Panics(func() { + RegisterProvider("test-pre-existent", func(m *Manager, cfg *config.StaticConfig) (ManagerProvider, error) { + return nil, nil + }) + }, "Registering a provider with an existing strategy should panic") + }) +} + +func (s *ProviderRegistryTestSuite) TestGetRegisteredStrategies() { + s.Run("With no registered providers, returns empty list", func() { + providerFactories = make(map[string]ProviderFactory) + strategies := GetRegisteredStrategies() + s.Empty(strategies, "No strategies should be registered") + }) + s.Run("With multiple registered providers, returns sorted list", func() { + providerFactories = make(map[string]ProviderFactory) + RegisterProvider("foo-strategy", func(m *Manager, cfg *config.StaticConfig) (ManagerProvider, error) { + return nil, nil + }) + RegisterProvider("bar-strategy", func(m *Manager, cfg *config.StaticConfig) (ManagerProvider, error) { + return nil, nil + }) + strategies := GetRegisteredStrategies() + expected := []string{"bar-strategy", "foo-strategy"} + s.Equal(expected, strategies, "Strategies should be sorted alphabetically") + }) +} + +func TestProviderRegistry(t *testing.T) { + suite.Run(t, new(ProviderRegistryTestSuite)) +} diff --git a/pkg/kubernetes/provider_test.go b/pkg/kubernetes/provider_test.go new file mode 100644 index 0000000..eca718f --- /dev/null +++ b/pkg/kubernetes/provider_test.go @@ -0,0 +1,127 @@ +package kubernetes + +import ( + "strings" + "testing" + + "github.com/containers/kubernetes-mcp-server/internal/test" + "github.com/containers/kubernetes-mcp-server/pkg/config" + "github.com/stretchr/testify/suite" + "k8s.io/client-go/rest" +) + +type BaseProviderSuite struct { + suite.Suite + originalProviderFactories map[string]ProviderFactory +} + +func (s *BaseProviderSuite) SetupTest() { + s.originalProviderFactories = make(map[string]ProviderFactory) + for k, v := range providerFactories { + s.originalProviderFactories[k] = v + } +} + +func (s *BaseProviderSuite) TearDownTest() { + providerFactories = make(map[string]ProviderFactory) + for k, v := range s.originalProviderFactories { + providerFactories[k] = v + } +} + +type ProviderTestSuite struct { + BaseProviderSuite +} + +func (s *ProviderTestSuite) TestNewManagerProviderInCluster() { + originalIsInClusterConfig := InClusterConfig + s.T().Cleanup(func() { + InClusterConfig = originalIsInClusterConfig + }) + InClusterConfig = func() (*rest.Config, error) { + return &rest.Config{}, nil + } + s.Run("With no cluster_provider_strategy, returns single-cluster provider", func() { + cfg := test.Must(config.ReadToml([]byte{})) + provider, err := NewManagerProvider(cfg) + s.Require().NoError(err, "Expected no error for in-cluster provider") + s.NotNil(provider, "Expected provider instance") + s.IsType(&singleClusterProvider{}, provider, "Expected singleClusterProvider type") + }) + s.Run("With configured in-cluster cluster_provider_strategy, returns single-cluster provider", func() { + cfg := test.Must(config.ReadToml([]byte(` + cluster_provider_strategy = "in-cluster" + `))) + provider, err := NewManagerProvider(cfg) + s.Require().NoError(err, "Expected no error for single-cluster strategy") + s.NotNil(provider, "Expected provider instance") + s.IsType(&singleClusterProvider{}, provider, "Expected singleClusterProvider type") + }) + s.Run("With configured kubeconfig cluster_provider_strategy, returns error", func() { + cfg := test.Must(config.ReadToml([]byte(` + cluster_provider_strategy = "kubeconfig" + `))) + provider, err := NewManagerProvider(cfg) + s.Require().Error(err, "Expected error for kubeconfig strategy") + s.ErrorContains(err, "kubeconfig ClusterProviderStrategy is invalid for in-cluster deployments") + s.Nilf(provider, "Expected no provider instance, got %v", provider) + }) + s.Run("With configured non-existent cluster_provider_strategy, returns error", func() { + cfg := test.Must(config.ReadToml([]byte(` + cluster_provider_strategy = "i-do-not-exist" + `))) + provider, err := NewManagerProvider(cfg) + s.Require().Error(err, "Expected error for non-existent strategy") + s.ErrorContains(err, "no provider registered for strategy 'i-do-not-exist'") + s.Nilf(provider, "Expected no provider instance, got %v", provider) + }) +} + +func (s *ProviderTestSuite) TestNewManagerProviderLocal() { + mockServer := test.NewMockServer() + s.T().Cleanup(mockServer.Close) + kubeconfigPath := strings.ReplaceAll(mockServer.KubeconfigFile(s.T()), `\`, `\\`) + s.Run("With no cluster_provider_strategy, returns kubeconfig provider", func() { + cfg := test.Must(config.ReadToml([]byte(` + kubeconfig = "` + kubeconfigPath + `" + `))) + provider, err := NewManagerProvider(cfg) + s.Require().NoError(err, "Expected no error for kubeconfig provider") + s.NotNil(provider, "Expected provider instance") + s.IsType(&kubeConfigClusterProvider{}, provider, "Expected kubeConfigClusterProvider type") + }) + s.Run("With configured kubeconfig cluster_provider_strategy, returns kubeconfig provider", func() { + cfg := test.Must(config.ReadToml([]byte(` + kubeconfig = "` + kubeconfigPath + `" + cluster_provider_strategy = "kubeconfig" + `))) + provider, err := NewManagerProvider(cfg) + s.Require().NoError(err, "Expected no error for kubeconfig provider") + s.NotNil(provider, "Expected provider instance") + s.IsType(&kubeConfigClusterProvider{}, provider, "Expected kubeConfigClusterProvider type") + }) + s.Run("With configured in-cluster cluster_provider_strategy, returns error", func() { + cfg := test.Must(config.ReadToml([]byte(` + kubeconfig = "` + kubeconfigPath + `" + cluster_provider_strategy = "in-cluster" + `))) + provider, err := NewManagerProvider(cfg) + s.Require().Error(err, "Expected error for in-cluster strategy") + s.ErrorContains(err, "server must be deployed in cluster for the in-cluster ClusterProviderStrategy") + s.Nilf(provider, "Expected no provider instance, got %v", provider) + }) + s.Run("With configured non-existent cluster_provider_strategy, returns error", func() { + cfg := test.Must(config.ReadToml([]byte(` + kubeconfig = "` + kubeconfigPath + `" + cluster_provider_strategy = "i-do-not-exist" + `))) + provider, err := NewManagerProvider(cfg) + s.Require().Error(err, "Expected error for non-existent strategy") + s.ErrorContains(err, "no provider registered for strategy 'i-do-not-exist'") + s.Nilf(provider, "Expected no provider instance, got %v", provider) + }) +} + +func TestProvider(t *testing.T) { + suite.Run(t, new(ProviderTestSuite)) +}