diff --git a/pkg/toolsets/netedge/coredns.go b/pkg/toolsets/netedge/coredns.go index 267969977..6ade4bf2a 100644 --- a/pkg/toolsets/netedge/coredns.go +++ b/pkg/toolsets/netedge/coredns.go @@ -4,13 +4,11 @@ import ( "fmt" "github.com/containers/kubernetes-mcp-server/pkg/api" - "github.com/containers/kubernetes-mcp-server/pkg/kubernetes" "github.com/google/jsonschema-go/jsonschema" - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/rest" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/utils/ptr" - "sigs.k8s.io/controller-runtime/pkg/client" ) func initCoreDNS() []api.ServerTool { @@ -34,30 +32,27 @@ func initCoreDNS() []api.ServerTool { } } -// newClientFunc is the function used to create a controller-runtime client. -// It is a variable to allow overriding in tests. -var newClientFunc = func(config *rest.Config, options client.Options) (client.Client, error) { - return client.New(config, options) -} - func getCoreDNSConfig(params api.ToolHandlerParams) (*api.ToolCallResult, error) { - cfg := params.RESTConfig() - if cfg == nil { - return api.NewToolCallResult("", fmt.Errorf("failed to get REST config")), nil + gvr := schema.GroupVersionResource{ + Group: "", + Version: "v1", + Resource: "configmaps", } - cl, err := newClientFunc(cfg, client.Options{Scheme: kubernetes.Scheme}) + cm, err := params.DynamicClient().Resource(gvr).Namespace("openshift-dns").Get(params.Context, "dns-default", metav1.GetOptions{}) if err != nil { - return api.NewToolCallResult("", fmt.Errorf("failed to create controller-runtime client: %w", err)), nil + return api.NewToolCallResult("", fmt.Errorf("failed to get dns-default ConfigMap: %w", err)), nil } - cm := &corev1.ConfigMap{} - err = cl.Get(params.Context, types.NamespacedName{Name: "dns-default", Namespace: "openshift-dns"}, cm) + data, found, err := unstructured.NestedStringMap(cm.Object, "data") if err != nil { - return api.NewToolCallResult("", fmt.Errorf("failed to get dns-default ConfigMap: %w", err)), nil + return api.NewToolCallResult("", fmt.Errorf("failed to parse ConfigMap data: %w", err)), nil + } + if !found { + return api.NewToolCallResult("", fmt.Errorf("ConfigMap has no data")), nil } - corefile, ok := cm.Data["Corefile"] + corefile, ok := data["Corefile"] if !ok { return api.NewToolCallResult("", fmt.Errorf("corefile not found in dns-default ConfigMap")), nil } diff --git a/pkg/toolsets/netedge/coredns_test.go b/pkg/toolsets/netedge/coredns_test.go index 138b48490..d844aa6e0 100644 --- a/pkg/toolsets/netedge/coredns_test.go +++ b/pkg/toolsets/netedge/coredns_test.go @@ -1,31 +1,15 @@ package netedge import ( - "context" - "testing" - - "github.com/containers/kubernetes-mcp-server/pkg/api" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" - "k8s.io/client-go/rest" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/client/fake" + "k8s.io/client-go/dynamic/fake" + clientgoscheme "k8s.io/client-go/kubernetes/scheme" ) -// mockKubernetesClient implements api.KubernetesClient for testing -type mockKubernetesClient struct { - api.KubernetesClient - restConfig *rest.Config -} - -func (m *mockKubernetesClient) RESTConfig() *rest.Config { - return m.restConfig -} +func (s *NetEdgeTestSuite) TestGetCoreDNSConfig() { -func TestGetCoreDNSConfig(t *testing.T) { tests := []struct { name string configMap *corev1.ConfigMap @@ -72,39 +56,34 @@ func TestGetCoreDNSConfig(t *testing.T) { } for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { + s.Run(tt.name, func() { // Setup mock client objs := []runtime.Object{} if tt.configMap != nil { objs = append(objs, tt.configMap) } - // Override newClientFunc to return fake client - originalNewClientFunc := newClientFunc - defer func() { newClientFunc = originalNewClientFunc }() + // Setup fake dynamic client + scheme := runtime.NewScheme() + _ = clientgoscheme.AddToScheme(scheme) - newClientFunc = func(config *rest.Config, options client.Options) (client.Client, error) { - return fake.NewClientBuilder().WithRuntimeObjects(objs...).Build(), nil - } - - // Call handler - params := api.ToolHandlerParams{ - Context: context.Background(), - KubernetesClient: &mockKubernetesClient{restConfig: &rest.Config{}}, - } + // Create a fake dynamic client with the objects + dynClient := fake.NewSimpleDynamicClient(scheme, objs...) + s.SetDynamicClient(dynClient) - result, err := getCoreDNSConfig(params) + // Call handler using suite params + result, err := getCoreDNSConfig(s.params) if tt.expectError { - require.NoError(t, err) // Handler returns error in result, not as return value - require.NotNil(t, result) - require.Error(t, result.Error) - assert.Contains(t, result.Error.Error(), tt.errorContains) + s.Require().NoError(err) // Handler returns error in result, not as return value + s.Require().NotNil(result) + s.Require().Error(result.Error) + s.Assert().Contains(result.Error.Error(), tt.errorContains) } else { - require.NoError(t, err) - require.NotNil(t, result) - require.NoError(t, result.Error) - assert.Equal(t, tt.expectedOutput, result.Content) + s.Require().NoError(err) + s.Require().NotNil(result) + s.Require().NoError(result.Error) + s.Assert().Equal(tt.expectedOutput, result.Content) } }) } diff --git a/pkg/toolsets/netedge/suite_test.go b/pkg/toolsets/netedge/suite_test.go new file mode 100644 index 000000000..a988deda7 --- /dev/null +++ b/pkg/toolsets/netedge/suite_test.go @@ -0,0 +1,66 @@ +package netedge + +import ( + "context" + "testing" + + "github.com/containers/kubernetes-mcp-server/pkg/api" + "github.com/stretchr/testify/suite" + "k8s.io/client-go/dynamic" + "k8s.io/client-go/rest" +) + +// mockKubernetesClient implements api.KubernetesClient for testing +type mockKubernetesClient struct { + api.KubernetesClient + restConfig *rest.Config + dynamicClient dynamic.Interface +} + +func (m *mockKubernetesClient) RESTConfig() *rest.Config { + return m.restConfig +} + +func (m *mockKubernetesClient) DynamicClient() dynamic.Interface { + return m.dynamicClient +} + +type NetEdgeTestSuite struct { + suite.Suite + params api.ToolHandlerParams + mockReq *mockToolCallRequest + mockClient *mockKubernetesClient +} + +func (s *NetEdgeTestSuite) SetupTest() { + s.mockReq = &mockToolCallRequest{args: make(map[string]interface{})} + s.mockClient = &mockKubernetesClient{ + restConfig: &rest.Config{}, + } + s.params = api.ToolHandlerParams{ + Context: context.Background(), + ToolCallRequest: s.mockReq, + KubernetesClient: s.mockClient, + } +} + +func (s *NetEdgeTestSuite) SetArgs(args map[string]interface{}) { + s.mockReq.args = args +} + +func (s *NetEdgeTestSuite) SetDynamicClient(dynClient dynamic.Interface) { + s.mockClient.dynamicClient = dynClient + s.params.KubernetesClient = s.mockClient +} + +func TestNetEdgeSuite(t *testing.T) { + suite.Run(t, new(NetEdgeTestSuite)) +} + +type mockToolCallRequest struct { + args map[string]any +} + +func (m *mockToolCallRequest) GetArguments() map[string]any { + return m.args +}