@@ -151,11 +151,48 @@ func (s *ContractTestSuite) requireSuccess(endpoint string, resp *http.Response,
151151 "Endpoint %s returned empty response body" , endpoint )
152152}
153153
154+ // requireValidJSON asserts the response body is valid JSON and returns the raw decoded value.
155+ func (s * ContractTestSuite ) requireValidJSON (endpoint string , body []byte ) interface {} {
156+ var parsed interface {}
157+ err := json .Unmarshal (body , & parsed )
158+ s .Require ().NoError (err , "Endpoint %s returned invalid JSON: %s" , endpoint , string (body ))
159+ return parsed
160+ }
161+
162+ // requireJSONObject asserts the response is a JSON object and returns it.
163+ func (s * ContractTestSuite ) requireJSONObject (endpoint string , body []byte ) map [string ]interface {} {
164+ parsed := s .requireValidJSON (endpoint , body )
165+ obj , ok := parsed .(map [string ]interface {})
166+ s .Require ().True (ok , "Endpoint %s expected JSON object, got %T" , endpoint , parsed )
167+ return obj
168+ }
169+
170+ // requireJSONKeys asserts the JSON object response contains all expected top-level keys.
171+ func (s * ContractTestSuite ) requireJSONKeys (endpoint string , body []byte , keys ... string ) map [string ]interface {} {
172+ obj := s .requireJSONObject (endpoint , body )
173+ for _ , key := range keys {
174+ s .Contains (obj , key , "Endpoint %s response missing expected key %q" , endpoint , key )
175+ }
176+ return obj
177+ }
178+
179+ // requireJSONString asserts the response is a JSON-encoded string (e.g. markdown text)
180+ // and returns the decoded string.
181+ func (s * ContractTestSuite ) requireJSONString (endpoint string , body []byte ) string {
182+ parsed := s .requireValidJSON (endpoint , body )
183+ str , ok := parsed .(string )
184+ s .Require ().True (ok , "Endpoint %s expected JSON string, got %T" , endpoint , parsed )
185+ s .Require ().NotEmpty (str , "Endpoint %s returned empty string" , endpoint )
186+ return str
187+ }
188+
154189func (s * ContractTestSuite ) TestGetMeshStatus () {
155190 s .Run ("returns mesh status with non-empty response" , func () {
156191 resp , body , err := s .mcpCall (tools .KialiGetMeshStatusEndpoint , nil )
157192 s .Require ().NoError (err )
158193 s .requireSuccess (tools .KialiGetMeshStatusEndpoint , resp , body )
194+ s .requireJSONKeys (tools .KialiGetMeshStatusEndpoint , body ,
195+ "components" , "environment" )
159196 })
160197}
161198
@@ -168,6 +205,8 @@ func (s *ContractTestSuite) TestGetMeshTrafficGraph() {
168205 resp , body , err := s .mcpCall (tools .KialiGetMeshTrafficGraphEndpoint , args )
169206 s .Require ().NoError (err )
170207 s .requireSuccess (tools .KialiGetMeshTrafficGraphEndpoint , resp , body )
208+ s .requireJSONKeys (tools .KialiGetMeshTrafficGraphEndpoint , body ,
209+ "nodes" , "graphType" )
171210 })
172211}
173212
@@ -180,6 +219,8 @@ func (s *ContractTestSuite) TestListOrGetResources() {
180219 resp , body , err := s .mcpCall (tools .KialiListOrGetResourcesEndpoint , args )
181220 s .Require ().NoError (err )
182221 s .requireSuccess (tools .KialiListOrGetResourcesEndpoint , resp , body )
222+ obj := s .requireJSONObject (tools .KialiListOrGetResourcesEndpoint , body )
223+ s .NotEmpty (obj , "list_or_get_resources response should have at least one cluster key" )
183224 })
184225
185226 s .Run ("lists workloads in test namespace" , func () {
@@ -190,6 +231,8 @@ func (s *ContractTestSuite) TestListOrGetResources() {
190231 resp , body , err := s .mcpCall (tools .KialiListOrGetResourcesEndpoint , args )
191232 s .Require ().NoError (err )
192233 s .requireSuccess (tools .KialiListOrGetResourcesEndpoint , resp , body )
234+ obj := s .requireJSONObject (tools .KialiListOrGetResourcesEndpoint , body )
235+ s .NotEmpty (obj , "list_or_get_resources response should have at least one cluster key" )
193236 })
194237}
195238
@@ -203,6 +246,8 @@ func (s *ContractTestSuite) TestGetMetrics() {
203246 resp , body , err := s .mcpCall (tools .KialiGetMetricsEndpoint , args )
204247 s .Require ().NoError (err )
205248 s .requireSuccess (tools .KialiGetMetricsEndpoint , resp , body )
249+ s .requireJSONKeys (tools .KialiGetMetricsEndpoint , body ,
250+ "overview" , "traffic" , "throughput" , "latency" )
206251 })
207252}
208253
@@ -215,6 +260,7 @@ func (s *ContractTestSuite) TestGetLogs() {
215260 resp , body , err := s .mcpCall (tools .KialiGetLogsEndpoint , args )
216261 s .Require ().NoError (err )
217262 s .requireSuccess (tools .KialiGetLogsEndpoint , resp , body )
263+ s .requireJSONString (tools .KialiGetLogsEndpoint , body )
218264 })
219265}
220266
@@ -227,6 +273,7 @@ func (s *ContractTestSuite) TestGetPodPerformance() {
227273 resp , body , err := s .mcpCall (tools .KialiGetPodPerformanceEndpoint , args )
228274 s .Require ().NoError (err )
229275 s .requireSuccess (tools .KialiGetPodPerformanceEndpoint , resp , body )
276+ s .requireJSONString (tools .KialiGetPodPerformanceEndpoint , body )
230277 })
231278}
232279
@@ -238,6 +285,7 @@ func (s *ContractTestSuite) TestManageIstioConfigRead() {
238285 resp , body , err := s .mcpCall (tools .KialiManageIstioConfigReadEndpoint , args )
239286 s .Require ().NoError (err )
240287 s .requireSuccess (tools .KialiManageIstioConfigReadEndpoint , resp , body )
288+ s .requireValidJSON (tools .KialiManageIstioConfigReadEndpoint , body )
241289 })
242290}
243291
@@ -277,6 +325,7 @@ func (s *ContractTestSuite) TestManageIstioConfigCRUD() {
277325 resp , body , err := s .mcpCall (tools .KialiManageIstioConfigEndpoint , args )
278326 s .Require ().NoError (err )
279327 s .requireSuccess (tools .KialiManageIstioConfigEndpoint , resp , body )
328+ s .requireValidJSON (tools .KialiManageIstioConfigEndpoint , body )
280329 })
281330
282331 s .Run ("deletes the ServiceEntry" , func () {
@@ -308,6 +357,8 @@ func (s *ContractTestSuite) TestListTraces() {
308357 s .Require ().NoError (err )
309358 if s .tracingOn {
310359 s .requireSuccess (tools .KialiListTracesEndpoint , resp , body )
360+ s .requireJSONKeys (tools .KialiListTracesEndpoint , body ,
361+ "summary" , "traces" )
311362 } else {
312363 s .requireNotToolNotFound (tools .KialiListTracesEndpoint , resp , body )
313364 }
0 commit comments