mirror of
https://github.com/containers/kubernetes-mcp-server.git
synced 2025-10-23 01:22:57 +03:00
test(profiles): bootstrap initial testing support for profiles
This commit is contained in:
@@ -92,6 +92,9 @@ func TestMain(m *testing.M) {
|
||||
}
|
||||
|
||||
type mcpContext struct {
|
||||
profile Profile
|
||||
before *func(*mcpContext)
|
||||
after *func(*mcpContext)
|
||||
ctx context.Context
|
||||
tempDir string
|
||||
cancel context.CancelFunc
|
||||
@@ -102,10 +105,13 @@ type mcpContext struct {
|
||||
|
||||
func (c *mcpContext) beforeEach(t *testing.T) {
|
||||
var err error
|
||||
c.ctx, c.cancel = context.WithCancel(context.Background())
|
||||
c.ctx, c.cancel = context.WithCancel(t.Context())
|
||||
c.tempDir = t.TempDir()
|
||||
c.withKubeConfig(nil)
|
||||
if c.mcpServer, err = NewSever(Configuration{Profile: &FullProfile{}}); err != nil {
|
||||
if c.before != nil {
|
||||
(*c.before)(c)
|
||||
}
|
||||
if c.mcpServer, err = NewSever(Configuration{Profile: c.profile}); err != nil {
|
||||
t.Fatal(err)
|
||||
return
|
||||
}
|
||||
@@ -129,6 +135,9 @@ func (c *mcpContext) beforeEach(t *testing.T) {
|
||||
}
|
||||
|
||||
func (c *mcpContext) afterEach() {
|
||||
if c.after != nil {
|
||||
(*c.after)(c)
|
||||
}
|
||||
c.cancel()
|
||||
c.mcpServer.Close()
|
||||
_ = c.mcpClient.Close()
|
||||
@@ -136,7 +145,10 @@ func (c *mcpContext) afterEach() {
|
||||
}
|
||||
|
||||
func testCase(t *testing.T, test func(c *mcpContext)) {
|
||||
mcpCtx := &mcpContext{}
|
||||
testCaseWithContext(t, &mcpContext{profile: &FullProfile{}}, test)
|
||||
}
|
||||
|
||||
func testCaseWithContext(t *testing.T, mcpCtx *mcpContext, test func(c *mcpContext)) {
|
||||
mcpCtx.beforeEach(t)
|
||||
defer mcpCtx.afterEach()
|
||||
test(mcpCtx)
|
||||
|
||||
@@ -6,8 +6,6 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"slices"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
@@ -49,80 +47,3 @@ func TestWatchKubeConfig(t *testing.T) {
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestTools(t *testing.T) {
|
||||
expectedNames := []string{
|
||||
"configuration_view",
|
||||
"events_list",
|
||||
"helm_install",
|
||||
"helm_list",
|
||||
"helm_uninstall",
|
||||
"namespaces_list",
|
||||
"pods_list",
|
||||
"pods_list_in_namespace",
|
||||
"pods_get",
|
||||
"pods_delete",
|
||||
"pods_log",
|
||||
"pods_run",
|
||||
"pods_exec",
|
||||
"resources_list",
|
||||
"resources_get",
|
||||
"resources_create_or_update",
|
||||
"resources_delete",
|
||||
}
|
||||
testCase(t, func(c *mcpContext) {
|
||||
tools, err := c.mcpClient.ListTools(c.ctx, mcp.ListToolsRequest{})
|
||||
t.Run("ListTools returns tools", func(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("call ListTools failed %v", err)
|
||||
return
|
||||
}
|
||||
})
|
||||
nameSet := make(map[string]bool)
|
||||
for _, tool := range tools.Tools {
|
||||
nameSet[tool.Name] = true
|
||||
}
|
||||
for _, name := range expectedNames {
|
||||
t.Run("ListTools has "+name+" tool", func(t *testing.T) {
|
||||
if nameSet[name] != true {
|
||||
t.Fatalf("tool %s not found", name)
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestToolsInOpenShift(t *testing.T) {
|
||||
testCase(t, func(c *mcpContext) {
|
||||
defer c.inOpenShift()() // n.b. two sets of parentheses to invoke the first function
|
||||
c.mcpServer.server.AddTools(c.mcpServer.initNamespaces()...)
|
||||
c.mcpServer.server.AddTools(c.mcpServer.initResources()...)
|
||||
tools, err := c.mcpClient.ListTools(c.ctx, mcp.ListToolsRequest{})
|
||||
t.Run("ListTools returns tools", func(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("call ListTools failed %v", err)
|
||||
}
|
||||
})
|
||||
t.Run("ListTools contains projects_list tool", func(t *testing.T) {
|
||||
idx := slices.IndexFunc(tools.Tools, func(tool mcp.Tool) bool {
|
||||
return tool.Name == "projects_list"
|
||||
})
|
||||
if idx == -1 {
|
||||
t.Fatalf("tool projects_list not found")
|
||||
}
|
||||
})
|
||||
t.Run("ListTools has resources_list tool with OpenShift hint", func(t *testing.T) {
|
||||
idx := slices.IndexFunc(tools.Tools, func(tool mcp.Tool) bool {
|
||||
return tool.Name == "resources_list"
|
||||
})
|
||||
if idx == -1 {
|
||||
t.Fatalf("tool resources_list not found")
|
||||
}
|
||||
if !strings.Contains(tools.Tools[idx].Description, ", route.openshift.io/v1 Route") {
|
||||
t.Fatalf("tool resources_list does not have OpenShift hint, got %s", tools.Tools[9].Description)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
94
pkg/mcp/profiles_test.go
Normal file
94
pkg/mcp/profiles_test.go
Normal file
@@ -0,0 +1,94 @@
|
||||
package mcp
|
||||
|
||||
import (
|
||||
"github.com/mark3labs/mcp-go/mcp"
|
||||
"slices"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestFullProfileTools(t *testing.T) {
|
||||
expectedNames := []string{
|
||||
"configuration_view",
|
||||
"events_list",
|
||||
"helm_install",
|
||||
"helm_list",
|
||||
"helm_uninstall",
|
||||
"namespaces_list",
|
||||
"pods_list",
|
||||
"pods_list_in_namespace",
|
||||
"pods_get",
|
||||
"pods_delete",
|
||||
"pods_log",
|
||||
"pods_run",
|
||||
"pods_exec",
|
||||
"resources_list",
|
||||
"resources_get",
|
||||
"resources_create_or_update",
|
||||
"resources_delete",
|
||||
}
|
||||
mcpCtx := &mcpContext{profile: &FullProfile{}}
|
||||
testCaseWithContext(t, mcpCtx, func(c *mcpContext) {
|
||||
tools, err := c.mcpClient.ListTools(c.ctx, mcp.ListToolsRequest{})
|
||||
t.Run("ListTools returns tools", func(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("call ListTools failed %v", err)
|
||||
return
|
||||
}
|
||||
})
|
||||
nameSet := make(map[string]bool)
|
||||
for _, tool := range tools.Tools {
|
||||
nameSet[tool.Name] = true
|
||||
}
|
||||
for _, name := range expectedNames {
|
||||
t.Run("ListTools has "+name+" tool", func(t *testing.T) {
|
||||
if nameSet[name] != true {
|
||||
t.Fatalf("tool %s not found", name)
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestFullProfileToolsInOpenShift(t *testing.T) {
|
||||
var after func(c *mcpContext)
|
||||
before := func(c *mcpContext) {
|
||||
cleanCrds := c.inOpenShift()
|
||||
after = func(_ *mcpContext) {
|
||||
cleanCrds()
|
||||
}
|
||||
}
|
||||
mcpCtx := &mcpContext{
|
||||
profile: &FullProfile{},
|
||||
before: &before,
|
||||
after: &after,
|
||||
}
|
||||
testCaseWithContext(t, mcpCtx, func(c *mcpContext) {
|
||||
tools, err := c.mcpClient.ListTools(c.ctx, mcp.ListToolsRequest{})
|
||||
t.Run("ListTools returns tools", func(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("call ListTools failed %v", err)
|
||||
}
|
||||
})
|
||||
t.Run("ListTools contains projects_list tool", func(t *testing.T) {
|
||||
idx := slices.IndexFunc(tools.Tools, func(tool mcp.Tool) bool {
|
||||
return tool.Name == "projects_list"
|
||||
})
|
||||
if idx == -1 {
|
||||
t.Fatalf("tool projects_list not found")
|
||||
}
|
||||
})
|
||||
t.Run("ListTools has resources_list tool with OpenShift hint", func(t *testing.T) {
|
||||
idx := slices.IndexFunc(tools.Tools, func(tool mcp.Tool) bool {
|
||||
return tool.Name == "resources_list"
|
||||
})
|
||||
if idx == -1 {
|
||||
t.Fatalf("tool resources_list not found")
|
||||
}
|
||||
if !strings.Contains(tools.Tools[idx].Description, ", route.openshift.io/v1 Route") {
|
||||
t.Fatalf("tool resources_list does not have OpenShift hint, got %s", tools.Tools[9].Description)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user