55	"slices" 
66	"testing" 
77
8+ 	"github.com/BurntSushi/toml" 
89	"github.com/mark3labs/mcp-go/mcp" 
10+ 	"github.com/stretchr/testify/suite" 
911	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 
1012	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 
1113	"k8s.io/apimachinery/pkg/runtime/schema" 
@@ -14,108 +16,100 @@ import (
1416
1517	"github.com/containers/kubernetes-mcp-server/internal/test" 
1618	"github.com/containers/kubernetes-mcp-server/pkg/config" 
17- 	"github.com/containers/kubernetes-mcp-server/pkg/output" 
1819)
1920
20- func   TestNamespacesList ( t   * testing. T )  {
21- 	testCase ( t ,  func ( c   * mcpContext ) { 
22- 		 c . withEnvTest () 
23- 		 toolResult ,  err   :=   c . callTool ( "namespaces_list" ,  map [ string ] interface {}{}) 
24- 		 t . Run ( "namespaces_list returns namespace list" ,  func ( t   * testing. T ) {
25- 			 if   err   !=   nil  { 
26- 				 t . Fatalf ( "call tool failed %v "err ) 
27- 			} 
28- 			 if   toolResult . IsError  {
29- 				 t . Fatalf ( "call tool failed"  )
30- 			} 
21+ type   NamespacesSuite   struct  {
22+ 	BaseMcpSuite 
23+ } 
24+ 
25+ func  ( s   * NamespacesSuite )  TestNamespacesList ( ) {
26+ 	s . InitMcpClient () 
27+ 	s . Run ( "namespaces_list "func () { 
28+ 		toolResult ,  err   :=   s . CallTool ( "namespaces_list" ,  map [ string ] interface {}{}) 
29+ 		s . Run ( "no error" ,  func ()  {
30+ 			s . Nilf ( err ,  "call tool failed %v"  ,  err )
31+ 			s . Falsef ( toolResult . IsError ,  "call tool failed" ) 
3132		})
33+ 		s .Require ().NotNil (toolResult , "Expected tool result from call" )
3234		var  decoded  []unstructured.Unstructured 
3335		err  =  yaml .Unmarshal ([]byte (toolResult .Content [0 ].(mcp.TextContent ).Text ), & decoded )
34- 		t .Run ("namespaces_list has yaml content" , func (t  * testing.T ) {
35- 			if  err  !=  nil  {
36- 				t .Fatalf ("invalid tool result content %v" , err )
37- 			}
36+ 		s .Run ("has yaml content" , func () {
37+ 			s .Nilf (err , "invalid tool result content %v" , err )
3838		})
39- 		t .Run ("namespaces_list returns at least 3 items" , func (t  * testing.T ) {
40- 			if  len (decoded ) <  3  {
41- 				t .Errorf ("invalid namespace count, expected at least 3, got %v" , len (decoded ))
42- 			}
39+ 		s .Run ("returns at least 3 items" , func () {
40+ 			s .Truef (len (decoded ) >=  3 , "expected at least 3 items, got %v" , len (decoded ))
4341			for  _ , expectedNamespace  :=  range  []string {"default" , "ns-1" , "ns-2" } {
44- 				idx   :=   slices .IndexFunc (decoded , func (ns  unstructured.Unstructured ) bool  {
42+ 				s . Truef ( slices .ContainsFunc (decoded , func (ns  unstructured.Unstructured ) bool  {
4543					return  ns .GetName () ==  expectedNamespace 
46- 				})
47- 				if  idx  ==  - 1  {
48- 					t .Errorf ("namespace %s not found in the list" , expectedNamespace )
49- 				}
44+ 				}), "namespace %s not found in the list" , expectedNamespace )
5045			}
5146		})
5247	})
5348}
5449
55- func  TestNamespacesListDenied ( t   * testing. T ) {
56- 	deniedResourcesServer   :=   test . Must ( config . ReadToml ([]byte (` 
50+ func  ( s   * NamespacesSuite )  TestNamespacesListDenied ( ) {
51+ 	s . Require (). NoError ( toml . Unmarshal ([]byte (` 
5752		denied_resources = [ { version = "v1", kind = "Namespace" } ] 
58- 	` )))
59- 	testCaseWithContext (t , & mcpContext {staticConfig : deniedResourcesServer }, func (c  * mcpContext ) {
60- 		c .withEnvTest ()
61- 		namespacesList , _  :=  c .callTool ("namespaces_list" , map [string ]interface {}{})
62- 		t .Run ("namespaces_list has error" , func (t  * testing.T ) {
63- 			if  ! namespacesList .IsError  {
64- 				t .Fatalf ("call tool should fail" )
65- 			}
53+ 	` ), s .Cfg ), "Expected to parse denied resources  config" )
54+ 	s .InitMcpClient ()
55+ 	s .Run ("namespaces_list (denied)" , func () {
56+ 		toolResult , err  :=  s .CallTool ("namespaces_list" , map [string ]interface {}{})
57+ 		s .Run ("has error" , func () {
58+ 			s .Truef (toolResult .IsError , "call tool should fail" )
59+ 			s .Nilf (err , "call tool should not return error object" )
6660		})
67- 		t .Run ("namespaces_list  describes denial" , func (t   * testing. T ) {
61+ 		s .Run ("describes denial" , func () {
6862			expectedMessage  :=  "failed to list namespaces: resource not allowed: /v1, Kind=Namespace" 
69- 			if  namespacesList .Content [0 ].(mcp.TextContent ).Text  !=  expectedMessage  {
70- 				t .Fatalf ("expected descriptive error '%s', got %v" , expectedMessage , namespacesList .Content [0 ].(mcp.TextContent ).Text )
71- 			}
63+ 			s .Equalf (expectedMessage , toolResult .Content [0 ].(mcp.TextContent ).Text ,
64+ 				"expected descriptive error '%s', got %v" , expectedMessage , toolResult .Content [0 ].(mcp.TextContent ).Text )
7265		})
7366	})
7467}
7568
76- func  TestNamespacesListAsTable (t  * testing.T ) {
77- 	testCaseWithContext (t , & mcpContext {listOutput : output .Table }, func (c  * mcpContext ) {
78- 		c .withEnvTest ()
79- 		toolResult , err  :=  c .callTool ("namespaces_list" , map [string ]interface {}{})
80- 		t .Run ("namespaces_list returns namespace list" , func (t  * testing.T ) {
81- 			if  err  !=  nil  {
82- 				t .Fatalf ("call tool failed %v" , err )
83- 			}
84- 			if  toolResult .IsError  {
85- 				t .Fatalf ("call tool failed" )
86- 			}
69+ func  (s  * NamespacesSuite ) TestNamespacesListAsTable () {
70+ 	s .Cfg .ListOutput  =  "table" 
71+ 	s .InitMcpClient ()
72+ 	s .Run ("namespaces_list (list_output=table)" , func () {
73+ 		toolResult , err  :=  s .CallTool ("namespaces_list" , map [string ]interface {}{})
74+ 		s .Run ("no error" , func () {
75+ 			s .Nilf (err , "call tool failed %v" , err )
76+ 			s .Falsef (toolResult .IsError , "call tool failed" )
8777		})
78+ 		s .Require ().NotNil (toolResult , "Expected tool result from call" )
8879		out  :=  toolResult .Content [0 ].(mcp.TextContent ).Text 
89- 		t .Run ("namespaces_list  returns column headers" , func (t   * testing. T ) {
80+ 		s .Run ("returns column headers" , func () {
9081			expectedHeaders  :=  "APIVERSION\\ s+KIND\\ s+NAME\\ s+STATUS\\ s+AGE\\ s+LABELS" 
91- 			if   m , e  :=  regexp .MatchString (expectedHeaders , out );  ! m   ||   e   !=   nil  { 
92- 				 t . Fatalf ( "Expected headers '%s' not found in output:\n %s" , expectedHeaders , out )
93- 			} 
82+ 			m , e  :=  regexp .MatchString (expectedHeaders , out )
83+ 			s . Truef ( m ,  "Expected headers '%s' not found in output:\n %s" , expectedHeaders , out )
84+ 			s . NoErrorf ( e ,  "Error matching headers regex: %v" ,  e ) 
9485		})
95- 		t .Run ("namespaces_list  returns formatted row for ns-1" , func (t   * testing. T ) {
86+ 		s .Run ("returns formatted row for ns-1" , func () {
9687			expectedRow  :=  "(?<apiVersion>v1)\\ s+"  + 
9788				"(?<kind>Namespace)\\ s+"  + 
9889				"(?<name>ns-1)\\ s+"  + 
9990				"(?<status>Active)\\ s+"  + 
10091				"(?<age>(\\ d+m)?(\\ d+s)?)\\ s+"  + 
10192				"(?<labels>kubernetes.io/metadata.name=ns-1)" 
102- 			if   m , e  :=  regexp .MatchString (expectedRow , out );  ! m   ||   e   !=   nil  { 
103- 				 t . Fatalf ( "Expected row '%s' not found in output:\n %s" , expectedRow , out )
104- 			} 
93+ 			m , e  :=  regexp .MatchString (expectedRow , out )
94+ 			s . Truef ( m ,  "Expected row '%s' not found in output:\n %s" , expectedRow , out )
95+ 			s . NoErrorf ( e ,  "Error matching ns-1 regex: %v" ,  e ) 
10596		})
106- 		t .Run ("namespaces_list  returns formatted row for ns-2" , func (t   * testing. T ) {
97+ 		s .Run ("returns formatted row for ns-2" , func () {
10798			expectedRow  :=  "(?<apiVersion>v1)\\ s+"  + 
10899				"(?<kind>Namespace)\\ s+"  + 
109100				"(?<name>ns-2)\\ s+"  + 
110101				"(?<status>Active)\\ s+"  + 
111102				"(?<age>(\\ d+m)?(\\ d+s)?)\\ s+"  + 
112103				"(?<labels>kubernetes.io/metadata.name=ns-2)" 
113- 			if   m , e  :=  regexp .MatchString (expectedRow , out );  ! m   ||   e   !=   nil  { 
114- 				 t . Fatalf ( "Expected row '%s' not found in output:\n %s" , expectedRow , out )
115- 			} 
104+ 			m , e  :=  regexp .MatchString (expectedRow , out )
105+ 			s . Truef ( m ,  "Expected row '%s' not found in output:\n %s" , expectedRow , out )
106+ 			s . NoErrorf ( e ,  "Error matching ns-2 regex: %v" ,  e ) 
116107		})
117108	})
109+ }
118110
111+ func  TestNamespaces (t  * testing.T ) {
112+ 	suite .Run (t , new (NamespacesSuite ))
119113}
120114
121115func  TestProjectsListInOpenShift (t  * testing.T ) {
0 commit comments