@@ -3,6 +3,7 @@ package mcp
3
3
import (
4
4
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
5
5
"sigs.k8s.io/yaml"
6
+ "strings"
6
7
"testing"
7
8
)
8
9
@@ -253,3 +254,153 @@ func TestPodsLog(t *testing.T) {
253
254
})
254
255
})
255
256
}
257
+
258
+ func TestPodsRun (t * testing.T ) {
259
+ testCase (t , func (c * mcpContext ) {
260
+ c .withEnvTest ()
261
+ t .Run ("pods_run with nil image returns error" , func (t * testing.T ) {
262
+ toolResult , _ := c .callTool ("pods_run" , map [string ]interface {}{})
263
+ if toolResult .IsError != true {
264
+ t .Errorf ("call tool should fail" )
265
+ return
266
+ }
267
+ if toolResult .Content [0 ].(map [string ]interface {})["text" ].(string ) != "failed to run pod, missing argument image" {
268
+ t .Errorf ("invalid error message, got %v" , toolResult .Content [0 ].(map [string ]interface {})["text" ].(string ))
269
+ return
270
+ }
271
+ })
272
+ podsRunNilNamespace , err := c .callTool ("pods_run" , map [string ]interface {}{"image" : "nginx" })
273
+ t .Run ("pods_run with image and nil namespace runs pod" , func (t * testing.T ) {
274
+ if err != nil {
275
+ t .Errorf ("call tool failed %v" , err )
276
+ return
277
+ }
278
+ if podsRunNilNamespace .IsError {
279
+ t .Errorf ("call tool failed" )
280
+ return
281
+ }
282
+ })
283
+ var decodedNilNamespace []unstructured.Unstructured
284
+ err = yaml .Unmarshal ([]byte (podsRunNilNamespace .Content [0 ].(map [string ]interface {})["text" ].(string )), & decodedNilNamespace )
285
+ t .Run ("pods_run with image and nil namespace has yaml content" , func (t * testing.T ) {
286
+ if err != nil {
287
+ t .Errorf ("invalid tool result content %v" , err )
288
+ return
289
+ }
290
+ })
291
+ t .Run ("pods_run with image and nil namespace returns 1 item (Pod)" , func (t * testing.T ) {
292
+ if len (decodedNilNamespace ) != 1 {
293
+ t .Errorf ("invalid pods count, expected 1, got %v" , len (decodedNilNamespace ))
294
+ return
295
+ }
296
+ if decodedNilNamespace [0 ].GetKind () != "Pod" {
297
+ t .Errorf ("invalid pod kind, expected Pod, got %v" , decodedNilNamespace [0 ].GetKind ())
298
+ return
299
+ }
300
+ })
301
+ t .Run ("pods_run with image and nil namespace returns pod in default" , func (t * testing.T ) {
302
+ if decodedNilNamespace [0 ].GetNamespace () != "default" {
303
+ t .Errorf ("invalid pod namespace, expected default, got %v" , decodedNilNamespace [0 ].GetNamespace ())
304
+ return
305
+ }
306
+ })
307
+ t .Run ("pods_run with image and nil namespace returns pod with random name" , func (t * testing.T ) {
308
+ if ! strings .HasPrefix (decodedNilNamespace [0 ].GetName (), "kubernetes-mcp-server-run-" ) {
309
+ t .Errorf ("invalid pod name, expected random, got %v" , decodedNilNamespace [0 ].GetName ())
310
+ return
311
+ }
312
+ })
313
+ t .Run ("pods_run with image and nil namespace returns pod with labels" , func (t * testing.T ) {
314
+ labels := decodedNilNamespace [0 ].Object ["metadata" ].(map [string ]interface {})["labels" ].(map [string ]interface {})
315
+ if labels ["app.kubernetes.io/name" ] == "" {
316
+ t .Errorf ("invalid labels, expected app.kubernetes.io/name, got %v" , labels )
317
+ return
318
+ }
319
+ if labels ["app.kubernetes.io/component" ] == "" {
320
+ t .Errorf ("invalid labels, expected app.kubernetes.io/component, got %v" , labels )
321
+ return
322
+ }
323
+ if labels ["app.kubernetes.io/managed-by" ] != "kubernetes-mcp-server" {
324
+ t .Errorf ("invalid labels, expected app.kubernetes.io/managed-by, got %v" , labels )
325
+ return
326
+ }
327
+ if labels ["app.kubernetes.io/part-of" ] != "kubernetes-mcp-server-run-sandbox" {
328
+ t .Errorf ("invalid labels, expected app.kubernetes.io/part-of, got %v" , labels )
329
+ return
330
+ }
331
+ })
332
+ t .Run ("pods_run with image and nil namespace returns pod with nginx container" , func (t * testing.T ) {
333
+ containers := decodedNilNamespace [0 ].Object ["spec" ].(map [string ]interface {})["containers" ].([]interface {})
334
+ if containers [0 ].(map [string ]interface {})["image" ] != "nginx" {
335
+ t .Errorf ("invalid container name, expected nginx, got %v" , containers [0 ].(map [string ]interface {})["image" ])
336
+ return
337
+ }
338
+ })
339
+
340
+ podsRunNamespaceAndPort , err := c .callTool ("pods_run" , map [string ]interface {}{"image" : "nginx" , "port" : 80 })
341
+ t .Run ("pods_run with image, namespace, and port runs pod" , func (t * testing.T ) {
342
+ if err != nil {
343
+ t .Errorf ("call tool failed %v" , err )
344
+ return
345
+ }
346
+ if podsRunNamespaceAndPort .IsError {
347
+ t .Errorf ("call tool failed" )
348
+ return
349
+ }
350
+ })
351
+ var decodedNamespaceAndPort []unstructured.Unstructured
352
+ err = yaml .Unmarshal ([]byte (podsRunNamespaceAndPort .Content [0 ].(map [string ]interface {})["text" ].(string )), & decodedNamespaceAndPort )
353
+ t .Run ("pods_run with image, namespace, and port has yaml content" , func (t * testing.T ) {
354
+ if err != nil {
355
+ t .Errorf ("invalid tool result content %v" , err )
356
+ return
357
+ }
358
+ })
359
+ t .Run ("pods_run with image, namespace, and port returns 2 items (Pod + Service)" , func (t * testing.T ) {
360
+ if len (decodedNamespaceAndPort ) != 2 {
361
+ t .Errorf ("invalid pods count, expected 2, got %v" , len (decodedNamespaceAndPort ))
362
+ return
363
+ }
364
+ if decodedNamespaceAndPort [0 ].GetKind () != "Pod" {
365
+ t .Errorf ("invalid pod kind, expected Pod, got %v" , decodedNamespaceAndPort [0 ].GetKind ())
366
+ return
367
+ }
368
+ if decodedNamespaceAndPort [1 ].GetKind () != "Service" {
369
+ t .Errorf ("invalid service kind, expected Service, got %v" , decodedNamespaceAndPort [1 ].GetKind ())
370
+ return
371
+ }
372
+ })
373
+ t .Run ("pods_run with image, namespace, and port returns pod with port" , func (t * testing.T ) {
374
+ containers := decodedNamespaceAndPort [0 ].Object ["spec" ].(map [string ]interface {})["containers" ].([]interface {})
375
+ ports := containers [0 ].(map [string ]interface {})["ports" ].([]interface {})
376
+ if ports [0 ].(map [string ]interface {})["containerPort" ] != int64 (80 ) {
377
+ t .Errorf ("invalid container port, expected 80, got %v" , ports [0 ].(map [string ]interface {})["containerPort" ])
378
+ return
379
+ }
380
+ })
381
+ t .Run ("pods_run with image, namespace, and port returns service with port and selector" , func (t * testing.T ) {
382
+ ports := decodedNamespaceAndPort [1 ].Object ["spec" ].(map [string ]interface {})["ports" ].([]interface {})
383
+ if ports [0 ].(map [string ]interface {})["port" ] != int64 (80 ) {
384
+ t .Errorf ("invalid service port, expected 80, got %v" , ports [0 ].(map [string ]interface {})["port" ])
385
+ return
386
+ }
387
+ if ports [0 ].(map [string ]interface {})["targetPort" ] != int64 (80 ) {
388
+ t .Errorf ("invalid service target port, expected 80, got %v" , ports [0 ].(map [string ]interface {})["targetPort" ])
389
+ return
390
+ }
391
+ selector := decodedNamespaceAndPort [1 ].Object ["spec" ].(map [string ]interface {})["selector" ].(map [string ]interface {})
392
+ if selector ["app.kubernetes.io/name" ] == "" {
393
+ t .Errorf ("invalid service selector, expected app.kubernetes.io/name, got %v" , selector )
394
+ return
395
+ }
396
+ if selector ["app.kubernetes.io/managed-by" ] != "kubernetes-mcp-server" {
397
+ t .Errorf ("invalid service selector, expected app.kubernetes.io/managed-by, got %v" , selector )
398
+ return
399
+ }
400
+ if selector ["app.kubernetes.io/part-of" ] != "kubernetes-mcp-server-run-sandbox" {
401
+ t .Errorf ("invalid service selector, expected app.kubernetes.io/part-of, got %v" , selector )
402
+ return
403
+ }
404
+ })
405
+ })
406
+ }
0 commit comments