...

Source file src/k8s.io/kubectl/pkg/cmd/apiresources/apiresources_test.go

Documentation: k8s.io/kubectl/pkg/cmd/apiresources

     1  /*
     2  Copyright 2022 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package apiresources
    18  
    19  import (
    20  	"testing"
    21  
    22  	"github.com/spf13/cobra"
    23  
    24  	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    25  	"k8s.io/cli-runtime/pkg/genericiooptions"
    26  	cmdtesting "k8s.io/kubectl/pkg/cmd/testing"
    27  )
    28  
    29  func TestAPIResourcesComplete(t *testing.T) {
    30  	tf := cmdtesting.NewTestFactory()
    31  	defer tf.Cleanup()
    32  	cmd := NewCmdAPIResources(tf, genericiooptions.NewTestIOStreamsDiscard())
    33  	parentCmd := &cobra.Command{Use: "kubectl"}
    34  	parentCmd.AddCommand(cmd)
    35  	o := NewAPIResourceOptions(genericiooptions.NewTestIOStreamsDiscard())
    36  
    37  	err := o.Complete(tf, cmd, []string{})
    38  	if err != nil {
    39  		t.Fatalf("Unexpected error: %v", err)
    40  	}
    41  
    42  	err = o.Complete(tf, cmd, []string{"foo"})
    43  	if err == nil {
    44  		t.Fatalf("An error was expected but not returned")
    45  	}
    46  	expectedError := `unexpected arguments: [foo]
    47  See 'kubectl api-resources -h' for help and examples`
    48  	if err.Error() != expectedError {
    49  		t.Fatalf("Unexpected error: %v\n expected: %v", err, expectedError)
    50  	}
    51  }
    52  
    53  func TestAPIResourcesValidate(t *testing.T) {
    54  	testCases := []struct {
    55  		name          string
    56  		optionSetupFn func(o *APIResourceOptions)
    57  		expectedError string
    58  	}{
    59  		{
    60  			name:          "no errors",
    61  			optionSetupFn: func(o *APIResourceOptions) {},
    62  			expectedError: "",
    63  		},
    64  		{
    65  			name: "invalid output",
    66  			optionSetupFn: func(o *APIResourceOptions) {
    67  				o.Output = "foo"
    68  			},
    69  			expectedError: "--output foo is not available",
    70  		},
    71  		{
    72  			name: "invalid sort by",
    73  			optionSetupFn: func(o *APIResourceOptions) {
    74  				o.SortBy = "foo"
    75  			},
    76  			expectedError: "--sort-by accepts only name or kind",
    77  		},
    78  	}
    79  
    80  	for _, tc := range testCases {
    81  		t.Run(tc.name, func(tt *testing.T) {
    82  			o := NewAPIResourceOptions(genericiooptions.NewTestIOStreamsDiscard())
    83  			tc.optionSetupFn(o)
    84  			err := o.Validate()
    85  			if tc.expectedError == "" {
    86  				if err != nil {
    87  					tt.Fatalf("Unexpected error: %v", err)
    88  				}
    89  			} else {
    90  				if err == nil {
    91  					tt.Fatalf("An error was expected but not returned")
    92  				}
    93  				if err.Error() != tc.expectedError {
    94  					tt.Fatalf("Unexpected error: %v, expected: %v", err, tc.expectedError)
    95  				}
    96  			}
    97  		})
    98  	}
    99  }
   100  
   101  func TestAPIResourcesRun(t *testing.T) {
   102  	dc := cmdtesting.NewFakeCachedDiscoveryClient()
   103  	dc.PreferredResources = []*v1.APIResourceList{
   104  		{
   105  			GroupVersion: "v1",
   106  			APIResources: []v1.APIResource{
   107  				{
   108  					Name:       "foos",
   109  					Namespaced: false,
   110  					Kind:       "Foo",
   111  					Verbs:      []string{"get", "list"},
   112  					ShortNames: []string{"f", "fo"},
   113  					Categories: []string{"some-category"},
   114  				},
   115  				{
   116  					Name:       "bars",
   117  					Namespaced: true,
   118  					Kind:       "Bar",
   119  					Verbs:      []string{"get", "list", "create"},
   120  					ShortNames: []string{},
   121  					Categories: []string{},
   122  				},
   123  			},
   124  		},
   125  		{
   126  			GroupVersion: "somegroup/v1",
   127  			APIResources: []v1.APIResource{
   128  				{
   129  					Name:       "bazzes",
   130  					Namespaced: true,
   131  					Kind:       "Baz",
   132  					Verbs:      []string{"get", "list", "create", "delete"},
   133  					ShortNames: []string{"b"},
   134  					Categories: []string{"some-category", "another-category"},
   135  				},
   136  				{
   137  					Name:       "NoVerbs",
   138  					Namespaced: true,
   139  					Kind:       "NoVerbs",
   140  					Verbs:      []string{},
   141  					ShortNames: []string{"b"},
   142  					Categories: []string{},
   143  				},
   144  			},
   145  		},
   146  		{
   147  			GroupVersion: "someothergroup/v1",
   148  			APIResources: []v1.APIResource{},
   149  		},
   150  	}
   151  	tf := cmdtesting.NewTestFactory().WithDiscoveryClient(dc)
   152  	defer tf.Cleanup()
   153  
   154  	testCases := []struct {
   155  		name                  string
   156  		commandSetupFn        func(cmd *cobra.Command)
   157  		expectedOutput        string
   158  		expectedInvalidations int
   159  	}{
   160  		{
   161  			name:           "defaults",
   162  			commandSetupFn: func(cmd *cobra.Command) {},
   163  			expectedOutput: `NAME     SHORTNAMES   APIVERSION     NAMESPACED   KIND
   164  bars                  v1             true         Bar
   165  foos     f,fo         v1             false        Foo
   166  bazzes   b            somegroup/v1   true         Baz
   167  `,
   168  			expectedInvalidations: 1,
   169  		},
   170  		{
   171  			name: "no headers",
   172  			commandSetupFn: func(cmd *cobra.Command) {
   173  				cmd.Flags().Set("no-headers", "true")
   174  			},
   175  			expectedOutput: `bars            v1             true    Bar
   176  foos     f,fo   v1             false   Foo
   177  bazzes   b      somegroup/v1   true    Baz
   178  `,
   179  			expectedInvalidations: 1,
   180  		},
   181  		{
   182  			name: "specific api group",
   183  			commandSetupFn: func(cmd *cobra.Command) {
   184  				cmd.Flags().Set("api-group", "somegroup")
   185  			},
   186  			expectedOutput: `NAME     SHORTNAMES   APIVERSION     NAMESPACED   KIND
   187  bazzes   b            somegroup/v1   true         Baz
   188  `,
   189  			expectedInvalidations: 1,
   190  		},
   191  		{
   192  			name: "output wide",
   193  			commandSetupFn: func(cmd *cobra.Command) {
   194  				cmd.Flags().Set("output", "wide")
   195  			},
   196  			expectedOutput: `NAME     SHORTNAMES   APIVERSION     NAMESPACED   KIND   VERBS                    CATEGORIES
   197  bars                  v1             true         Bar    get,list,create          
   198  foos     f,fo         v1             false        Foo    get,list                 some-category
   199  bazzes   b            somegroup/v1   true         Baz    get,list,create,delete   some-category,another-category
   200  `,
   201  			expectedInvalidations: 1,
   202  		},
   203  		{
   204  			name: "output name",
   205  			commandSetupFn: func(cmd *cobra.Command) {
   206  				cmd.Flags().Set("output", "name")
   207  			},
   208  			expectedOutput: `bars
   209  foos
   210  bazzes.somegroup
   211  `,
   212  			expectedInvalidations: 1,
   213  		},
   214  		{
   215  			name: "namespaced",
   216  			commandSetupFn: func(cmd *cobra.Command) {
   217  				cmd.Flags().Set("namespaced", "true")
   218  			},
   219  			expectedOutput: `NAME     SHORTNAMES   APIVERSION     NAMESPACED   KIND
   220  bars                  v1             true         Bar
   221  bazzes   b            somegroup/v1   true         Baz
   222  `,
   223  			expectedInvalidations: 1,
   224  		},
   225  		{
   226  			name: "single verb",
   227  			commandSetupFn: func(cmd *cobra.Command) {
   228  				cmd.Flags().Set("verbs", "create")
   229  			},
   230  			expectedOutput: `NAME     SHORTNAMES   APIVERSION     NAMESPACED   KIND
   231  bars                  v1             true         Bar
   232  bazzes   b            somegroup/v1   true         Baz
   233  `,
   234  			expectedInvalidations: 1,
   235  		},
   236  		{
   237  			name: "multiple verbs",
   238  			commandSetupFn: func(cmd *cobra.Command) {
   239  				cmd.Flags().Set("verbs", "create,delete")
   240  			},
   241  			expectedOutput: `NAME     SHORTNAMES   APIVERSION     NAMESPACED   KIND
   242  bazzes   b            somegroup/v1   true         Baz
   243  `,
   244  			expectedInvalidations: 1,
   245  		},
   246  		{
   247  			name: "single category",
   248  			commandSetupFn: func(cmd *cobra.Command) {
   249  				cmd.Flags().Set("categories", "some-category")
   250  			},
   251  			expectedOutput: `NAME     SHORTNAMES   APIVERSION     NAMESPACED   KIND
   252  foos     f,fo         v1             false        Foo
   253  bazzes   b            somegroup/v1   true         Baz
   254  `,
   255  			expectedInvalidations: 1,
   256  		},
   257  		{
   258  			name: "multiple categories",
   259  			commandSetupFn: func(cmd *cobra.Command) {
   260  				cmd.Flags().Set("categories", "some-category,another-category")
   261  			},
   262  			expectedOutput: `NAME     SHORTNAMES   APIVERSION     NAMESPACED   KIND
   263  bazzes   b            somegroup/v1   true         Baz
   264  `,
   265  			expectedInvalidations: 1,
   266  		},
   267  		{
   268  			name: "sort by name",
   269  			commandSetupFn: func(cmd *cobra.Command) {
   270  				cmd.Flags().Set("sort-by", "name")
   271  			},
   272  			expectedOutput: `NAME     SHORTNAMES   APIVERSION     NAMESPACED   KIND
   273  bars                  v1             true         Bar
   274  bazzes   b            somegroup/v1   true         Baz
   275  foos     f,fo         v1             false        Foo
   276  `,
   277  			expectedInvalidations: 1,
   278  		},
   279  		{
   280  			name: "sort by kind",
   281  			commandSetupFn: func(cmd *cobra.Command) {
   282  				cmd.Flags().Set("sort-by", "kind")
   283  			},
   284  			expectedOutput: `NAME     SHORTNAMES   APIVERSION     NAMESPACED   KIND
   285  bars                  v1             true         Bar
   286  bazzes   b            somegroup/v1   true         Baz
   287  foos     f,fo         v1             false        Foo
   288  `,
   289  			expectedInvalidations: 1,
   290  		},
   291  		{
   292  			name: "cached",
   293  			commandSetupFn: func(cmd *cobra.Command) {
   294  				cmd.Flags().Set("cached", "true")
   295  			},
   296  			expectedOutput: `NAME     SHORTNAMES   APIVERSION     NAMESPACED   KIND
   297  bars                  v1             true         Bar
   298  foos     f,fo         v1             false        Foo
   299  bazzes   b            somegroup/v1   true         Baz
   300  `,
   301  			expectedInvalidations: 0,
   302  		},
   303  	}
   304  
   305  	for _, tc := range testCases {
   306  		t.Run(tc.name, func(tt *testing.T) {
   307  			dc.Invalidations = 0
   308  			ioStreams, _, out, errOut := genericiooptions.NewTestIOStreams()
   309  			cmd := NewCmdAPIResources(tf, ioStreams)
   310  			tc.commandSetupFn(cmd)
   311  			cmd.Run(cmd, []string{})
   312  
   313  			if errOut.Len() > 0 {
   314  				t.Fatalf("unexpected error output: %s", errOut.String())
   315  			}
   316  			if out.String() != tc.expectedOutput {
   317  				tt.Fatalf("unexpected output: %s\nexpected: %s", out.String(), tc.expectedOutput)
   318  			}
   319  			if dc.Invalidations != tc.expectedInvalidations {
   320  				tt.Fatalf("unexpected invalidations: %d, expected: %d", dc.Invalidations, tc.expectedInvalidations)
   321  			}
   322  		})
   323  	}
   324  }
   325  

View as plain text