Skip to content

Commit abbb661

Browse files
authored
test(kiali): move tests to MCP layer (#562)
Signed-off-by: Marc Nuri <[email protected]>
1 parent 45801d2 commit abbb661

File tree

2 files changed

+134
-66
lines changed

2 files changed

+134
-66
lines changed

pkg/kiali/mesh_test.go

Lines changed: 0 additions & 66 deletions
This file was deleted.

pkg/mcp/kiali_test.go

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
package mcp
2+
3+
import (
4+
"fmt"
5+
"net/http"
6+
"net/url"
7+
"slices"
8+
"sync"
9+
"testing"
10+
11+
"github.com/containers/kubernetes-mcp-server/internal/test"
12+
"github.com/containers/kubernetes-mcp-server/pkg/config"
13+
"github.com/mark3labs/mcp-go/mcp"
14+
"github.com/stretchr/testify/suite"
15+
)
16+
17+
type KialiSuite struct {
18+
BaseMcpSuite
19+
mockServer *test.MockServer
20+
}
21+
22+
func (s *KialiSuite) SetupTest() {
23+
s.BaseMcpSuite.SetupTest()
24+
s.mockServer = test.NewMockServer()
25+
s.mockServer.Config().BearerToken = "token-xyz"
26+
kubeConfig := s.Cfg.KubeConfig
27+
s.Cfg = test.Must(config.ReadToml([]byte(fmt.Sprintf(`
28+
toolsets = ["kiali"]
29+
[toolset_configs.kiali]
30+
url = "%s"
31+
`, s.mockServer.Config().Host))))
32+
s.Cfg.KubeConfig = kubeConfig
33+
}
34+
35+
func (s *KialiSuite) TearDownTest() {
36+
s.BaseMcpSuite.TearDownTest()
37+
if s.mockServer != nil {
38+
s.mockServer.Close()
39+
}
40+
}
41+
42+
func (s *KialiSuite) TestGetTraces() {
43+
var capturedURL *url.URL
44+
s.mockServer.Handle(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
45+
u := *r.URL
46+
capturedURL = &u
47+
_, _ = w.Write([]byte(`{"traceId":"test-trace-123","spans":[]}`))
48+
}))
49+
s.InitMcpClient()
50+
51+
s.Run("get_traces(traceId = 'test-trace-123')", func() {
52+
traceId := "test-trace-123"
53+
toolResult, err := s.CallTool("kiali_get_traces", map[string]interface{}{
54+
"traceId": traceId,
55+
})
56+
s.Run("no error", func() {
57+
s.Nilf(err, "call tool failed %v", err)
58+
s.Falsef(toolResult.IsError, "call tool failed")
59+
})
60+
s.Run("path is correct", func() {
61+
s.Equal("/api/traces/test-trace-123", capturedURL.Path, "Unexpected path")
62+
})
63+
s.Run("response contains trace ID", func() {
64+
s.Contains(toolResult.Content[0].(mcp.TextContent).Text, traceId, "Response should contain trace ID")
65+
})
66+
})
67+
}
68+
69+
func (s *KialiSuite) TestMeshGraph() {
70+
var capturedUrls []url.URL
71+
mu := sync.Mutex{}
72+
s.mockServer.Handle(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
73+
mu.Lock()
74+
defer mu.Unlock()
75+
capturedUrls = append(capturedUrls, *r.URL)
76+
_, _ = w.Write([]byte("{}"))
77+
}))
78+
s.InitMcpClient()
79+
80+
s.Run("mesh_graph() with defaults", func() {
81+
toolResult, err := s.CallTool("kiali_mesh_graph", map[string]interface{}{})
82+
s.Run("no error", func() {
83+
s.Nilf(err, "call tool failed %v", err)
84+
s.Falsef(toolResult.IsError, "call tool failed")
85+
})
86+
s.Run("performs 4 simultaneous requests", func() {
87+
s.Equal(4, len(capturedUrls), "expected 4 requests to Kiali")
88+
})
89+
s.Run("retrieves graph data", func() {
90+
i := slices.IndexFunc(capturedUrls, func(capturedUrl url.URL) bool {
91+
return capturedUrl.Path == "/api/namespaces/graph"
92+
})
93+
s.Require().NotEqual(-1, i, "expected request to /api/namespaces/graph")
94+
s.Run("requested with correct query parameters", func() {
95+
s.Equal("", capturedUrls[i].Query().Get("namespaces"), "Unexpected namespaces query parameter")
96+
s.Equal("false", capturedUrls[i].Query().Get("includeIdleEdges"), "Unexpected includeIdleEdges query parameter")
97+
s.Equal("true", capturedUrls[i].Query().Get("injectServiceNodes"), "Unexpected injectServiceNodes query parameter")
98+
s.Equal("cluster,namespace,app", capturedUrls[i].Query().Get("boxBy"), "Unexpected boxBy query parameter")
99+
s.Equal("none", capturedUrls[i].Query().Get("ambientTraffic"), "Unexpected ambientTraffic query parameter")
100+
s.Equal("deadNode,istio,serviceEntry,meshCheck,workloadEntry,health", capturedUrls[i].Query().Get("appenders"), "Unexpected appenders query parameter")
101+
s.Equal("requests", capturedUrls[i].Query().Get("rateGrpc"), "Unexpected rateGrpc query parameter")
102+
s.Equal("requests", capturedUrls[i].Query().Get("rateHttp"), "Unexpected rateHttp query parameter")
103+
s.Equal("sent", capturedUrls[i].Query().Get("rateTcp"), "Unexpected rateTcp query parameter")
104+
})
105+
})
106+
s.Run("retrieves mesh status", func() {
107+
i := slices.IndexFunc(capturedUrls, func(capturedUrl url.URL) bool {
108+
return capturedUrl.Path == "/api/mesh/graph"
109+
})
110+
s.Require().NotEqual(-1, i, "expected request to /api/mesh/graph")
111+
s.Run("requested with correct query parameters", func() {
112+
s.Equal("false", capturedUrls[i].Query().Get("includeGateways"), "Unexpected includeGateways query parameter")
113+
s.Equal("false", capturedUrls[i].Query().Get("includeWaypoints"), "Unexpected includeWaypoints query parameter")
114+
})
115+
})
116+
s.Run("retrieves namespaces", func() {
117+
i := slices.IndexFunc(capturedUrls, func(capturedUrl url.URL) bool {
118+
return capturedUrl.Path == "/api/namespaces"
119+
})
120+
s.Require().NotEqual(-1, i, "expected request to /api/namespaces")
121+
})
122+
s.Run("retrieves health data", func() {
123+
i := slices.IndexFunc(capturedUrls, func(capturedUrl url.URL) bool {
124+
return capturedUrl.Path == "/api/clusters/health"
125+
})
126+
s.Require().NotEqual(-1, i, "expected request to /api/clusters/health")
127+
})
128+
})
129+
130+
}
131+
132+
func TestKiali(t *testing.T) {
133+
suite.Run(t, new(KialiSuite))
134+
}

0 commit comments

Comments
 (0)