...

Source file src/k8s.io/kubectl/pkg/util/completion/completion_test.go

Documentation: k8s.io/kubectl/pkg/util/completion

     1  /*
     2  Copyright 2021 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 completion
    18  
    19  import (
    20  	"net/http"
    21  	"sort"
    22  	"testing"
    23  
    24  	"github.com/spf13/cobra"
    25  
    26  	"k8s.io/cli-runtime/pkg/genericiooptions"
    27  	"k8s.io/cli-runtime/pkg/resource"
    28  	"k8s.io/client-go/rest/fake"
    29  	"k8s.io/client-go/tools/clientcmd"
    30  	"k8s.io/client-go/tools/clientcmd/api"
    31  	"k8s.io/kubectl/pkg/cmd/get"
    32  	cmdtesting "k8s.io/kubectl/pkg/cmd/testing"
    33  	"k8s.io/kubectl/pkg/scheme"
    34  )
    35  
    36  func TestClusterCompletionFunc(t *testing.T) {
    37  	setMockFactory(api.Config{
    38  		Clusters: map[string]*api.Cluster{
    39  			"bar": {},
    40  			"baz": {},
    41  			"foo": {},
    42  		},
    43  	})
    44  
    45  	comps, directive := ClusterCompletionFunc(nil, []string{}, "")
    46  	checkCompletion(t, comps, []string{"bar", "baz", "foo"}, directive, cobra.ShellCompDirectiveNoFileComp)
    47  
    48  	comps, directive = ClusterCompletionFunc(nil, []string{}, "b")
    49  	checkCompletion(t, comps, []string{"bar", "baz"}, directive, cobra.ShellCompDirectiveNoFileComp)
    50  
    51  	comps, directive = ClusterCompletionFunc(nil, []string{}, "ba")
    52  	checkCompletion(t, comps, []string{"bar", "baz"}, directive, cobra.ShellCompDirectiveNoFileComp)
    53  
    54  	comps, directive = ClusterCompletionFunc(nil, []string{}, "bar")
    55  	checkCompletion(t, comps, []string{"bar"}, directive, cobra.ShellCompDirectiveNoFileComp)
    56  
    57  	comps, directive = ClusterCompletionFunc(nil, []string{}, "bart")
    58  	checkCompletion(t, comps, []string{}, directive, cobra.ShellCompDirectiveNoFileComp)
    59  }
    60  
    61  func TestContextCompletionFunc(t *testing.T) {
    62  	setMockFactory(api.Config{
    63  		Contexts: map[string]*api.Context{
    64  			"bar": {},
    65  			"baz": {},
    66  			"foo": {},
    67  		},
    68  	})
    69  
    70  	comps, directive := ContextCompletionFunc(nil, []string{}, "")
    71  	checkCompletion(t, comps, []string{"bar", "baz", "foo"}, directive, cobra.ShellCompDirectiveNoFileComp)
    72  
    73  	comps, directive = ContextCompletionFunc(nil, []string{}, "b")
    74  	checkCompletion(t, comps, []string{"bar", "baz"}, directive, cobra.ShellCompDirectiveNoFileComp)
    75  
    76  	comps, directive = ContextCompletionFunc(nil, []string{}, "ba")
    77  	checkCompletion(t, comps, []string{"bar", "baz"}, directive, cobra.ShellCompDirectiveNoFileComp)
    78  
    79  	comps, directive = ContextCompletionFunc(nil, []string{}, "bar")
    80  	checkCompletion(t, comps, []string{"bar"}, directive, cobra.ShellCompDirectiveNoFileComp)
    81  
    82  	comps, directive = ContextCompletionFunc(nil, []string{}, "bart")
    83  	checkCompletion(t, comps, []string{}, directive, cobra.ShellCompDirectiveNoFileComp)
    84  }
    85  
    86  func TestUserCompletionFunc(t *testing.T) {
    87  	setMockFactory(api.Config{
    88  		AuthInfos: map[string]*api.AuthInfo{
    89  			"bar": {},
    90  			"baz": {},
    91  			"foo": {},
    92  		},
    93  	})
    94  
    95  	comps, directive := UserCompletionFunc(nil, []string{}, "")
    96  	checkCompletion(t, comps, []string{"bar", "baz", "foo"}, directive, cobra.ShellCompDirectiveNoFileComp)
    97  
    98  	comps, directive = UserCompletionFunc(nil, []string{}, "b")
    99  	checkCompletion(t, comps, []string{"bar", "baz"}, directive, cobra.ShellCompDirectiveNoFileComp)
   100  
   101  	comps, directive = UserCompletionFunc(nil, []string{}, "ba")
   102  	checkCompletion(t, comps, []string{"bar", "baz"}, directive, cobra.ShellCompDirectiveNoFileComp)
   103  
   104  	comps, directive = UserCompletionFunc(nil, []string{}, "bar")
   105  	checkCompletion(t, comps, []string{"bar"}, directive, cobra.ShellCompDirectiveNoFileComp)
   106  
   107  	comps, directive = UserCompletionFunc(nil, []string{}, "bart")
   108  	checkCompletion(t, comps, []string{}, directive, cobra.ShellCompDirectiveNoFileComp)
   109  }
   110  
   111  func TestResourceTypeAndNameCompletionFuncOneArg(t *testing.T) {
   112  	tf, cmd := prepareCompletionTest()
   113  	addPodsToFactory(tf)
   114  
   115  	compFunc := ResourceTypeAndNameCompletionFunc(tf)
   116  	comps, directive := compFunc(cmd, []string{"pod"}, "b")
   117  	checkCompletion(t, comps, []string{"bar"}, directive, cobra.ShellCompDirectiveNoFileComp)
   118  }
   119  
   120  func TestResourceTypeAndNameCompletionFuncRepeating(t *testing.T) {
   121  	tf, cmd := prepareCompletionTest()
   122  	addPodsToFactory(tf)
   123  
   124  	compFunc := ResourceTypeAndNameCompletionFunc(tf)
   125  	comps, directive := compFunc(cmd, []string{"pod", "bar"}, "")
   126  	// The other pods should be completed, but not the already specified ones
   127  	checkCompletion(t, comps, []string{"foo"}, directive, cobra.ShellCompDirectiveNoFileComp)
   128  }
   129  
   130  func TestResourceTypeAndNameCompletionFuncJointForm(t *testing.T) {
   131  	tf, cmd := prepareCompletionTest()
   132  	addPodsToFactory(tf)
   133  
   134  	compFunc := ResourceTypeAndNameCompletionFunc(tf)
   135  	comps, directive := compFunc(cmd, []string{}, "pod/b")
   136  	checkCompletion(t, comps, []string{"pod/bar"}, directive, cobra.ShellCompDirectiveNoFileComp)
   137  }
   138  
   139  func TestResourceTypeAndNameCompletionFuncJointFormRepeating(t *testing.T) {
   140  	tf, cmd := prepareCompletionTest()
   141  	addPodsToFactory(tf)
   142  
   143  	compFunc := ResourceTypeAndNameCompletionFunc(tf)
   144  	comps, directive := compFunc(cmd, []string{"pod/bar"}, "pod/")
   145  	// The other pods should be completed, but not the already specified ones
   146  	checkCompletion(t, comps, []string{"pod/foo"}, directive, cobra.ShellCompDirectiveNoFileComp)
   147  }
   148  
   149  func TestSpecifiedResourceTypeAndNameCompletionFuncNoArgs(t *testing.T) {
   150  	tf, cmd := prepareCompletionTest()
   151  	addPodsToFactory(tf)
   152  
   153  	compFunc := SpecifiedResourceTypeAndNameCompletionFunc(tf, []string{"pod", "service", "statefulset"})
   154  	comps, directive := compFunc(cmd, []string{}, "s")
   155  	checkCompletion(t, comps, []string{"service", "statefulset"}, directive, cobra.ShellCompDirectiveNoFileComp)
   156  }
   157  
   158  func TestSpecifiedResourceTypeAndNameCompletionFuncOneArg(t *testing.T) {
   159  	tf, cmd := prepareCompletionTest()
   160  	addPodsToFactory(tf)
   161  
   162  	compFunc := SpecifiedResourceTypeAndNameCompletionFunc(tf, []string{"pod"})
   163  	comps, directive := compFunc(cmd, []string{"pod"}, "b")
   164  	checkCompletion(t, comps, []string{"bar"}, directive, cobra.ShellCompDirectiveNoFileComp)
   165  }
   166  
   167  func TestSpecifiedResourceTypeAndNameCompletionFuncRepeating(t *testing.T) {
   168  	tf, cmd := prepareCompletionTest()
   169  	addPodsToFactory(tf)
   170  
   171  	compFunc := SpecifiedResourceTypeAndNameCompletionFunc(tf, []string{"pod"})
   172  	comps, directive := compFunc(cmd, []string{"pod", "bar"}, "")
   173  	// The other pods should be completed, but not the already specified ones
   174  	checkCompletion(t, comps, []string{"foo"}, directive, cobra.ShellCompDirectiveNoFileComp)
   175  }
   176  
   177  func TestSpecifiedResourceTypeAndNameCompletionFuncJointFormOneArg(t *testing.T) {
   178  	tf, cmd := prepareCompletionTest()
   179  	addPodsToFactory(tf)
   180  
   181  	compFunc := SpecifiedResourceTypeAndNameCompletionFunc(tf, []string{"pod"})
   182  	comps, directive := compFunc(cmd, []string{}, "pod/b")
   183  	checkCompletion(t, comps, []string{"pod/bar"}, directive, cobra.ShellCompDirectiveNoFileComp)
   184  }
   185  
   186  func TestSpecifiedResourceTypeAndNameCompletionFuncJointFormRepeating(t *testing.T) {
   187  	tf, cmd := prepareCompletionTest()
   188  	addPodsToFactory(tf)
   189  
   190  	compFunc := SpecifiedResourceTypeAndNameCompletionFunc(tf, []string{"pod"})
   191  	comps, directive := compFunc(cmd, []string{"pod/bar"}, "pod/")
   192  	// The other pods should be completed, but not the already specified ones
   193  	checkCompletion(t, comps, []string{"pod/foo"}, directive, cobra.ShellCompDirectiveNoFileComp)
   194  }
   195  func TestSpecifiedResourceTypeAndNameCompletionNoRepeatFuncOneArg(t *testing.T) {
   196  	tf, cmd := prepareCompletionTest()
   197  	addPodsToFactory(tf)
   198  
   199  	compFunc := SpecifiedResourceTypeAndNameNoRepeatCompletionFunc(tf, []string{"pod"})
   200  	comps, directive := compFunc(cmd, []string{"pod"}, "b")
   201  	checkCompletion(t, comps, []string{"bar"}, directive, cobra.ShellCompDirectiveNoFileComp)
   202  }
   203  
   204  func TestSpecifiedResourceTypeAndNameCompletionNoRepeatFuncMultiArg(t *testing.T) {
   205  	tf, cmd := prepareCompletionTest()
   206  	addPodsToFactory(tf)
   207  
   208  	compFunc := SpecifiedResourceTypeAndNameNoRepeatCompletionFunc(tf, []string{"pod"})
   209  	comps, directive := compFunc(cmd, []string{"pod", "bar"}, "")
   210  	// There should not be any more pods shown as this function should not repeat the completion
   211  	checkCompletion(t, comps, []string{}, directive, cobra.ShellCompDirectiveNoFileComp)
   212  }
   213  
   214  func TestSpecifiedResourceTypeAndNameCompletionNoRepeatFuncJointFormOneArg(t *testing.T) {
   215  	tf, cmd := prepareCompletionTest()
   216  	addPodsToFactory(tf)
   217  
   218  	compFunc := SpecifiedResourceTypeAndNameNoRepeatCompletionFunc(tf, []string{"pod"})
   219  	comps, directive := compFunc(cmd, []string{}, "pod/b")
   220  	checkCompletion(t, comps, []string{"pod/bar"}, directive, cobra.ShellCompDirectiveNoFileComp)
   221  }
   222  
   223  func TestSpecifiedResourceTypeAndNameCompletionNoRepeatFuncJointFormMultiArg(t *testing.T) {
   224  	tf, cmd := prepareCompletionTest()
   225  	addPodsToFactory(tf)
   226  
   227  	compFunc := SpecifiedResourceTypeAndNameNoRepeatCompletionFunc(tf, []string{"pod"})
   228  	comps, directive := compFunc(cmd, []string{"pod/bar"}, "pod/")
   229  	// There should not be any more pods shown as this function should not repeat the completion
   230  	checkCompletion(t, comps, []string{}, directive, cobra.ShellCompDirectiveNoFileComp)
   231  }
   232  
   233  func TestResourceNameCompletionFuncNoArgs(t *testing.T) {
   234  	tf, cmd := prepareCompletionTest()
   235  	addPodsToFactory(tf)
   236  
   237  	compFunc := ResourceNameCompletionFunc(tf, "pod")
   238  	comps, directive := compFunc(cmd, []string{}, "b")
   239  	checkCompletion(t, comps, []string{"bar"}, directive, cobra.ShellCompDirectiveNoFileComp)
   240  }
   241  
   242  func TestResourceNameCompletionFuncTooManyArgs(t *testing.T) {
   243  	tf, cmd := prepareCompletionTest()
   244  	addPodsToFactory(tf)
   245  
   246  	compFunc := ResourceNameCompletionFunc(tf, "pod")
   247  	comps, directive := compFunc(cmd, []string{"pod-name"}, "")
   248  	checkCompletion(t, comps, []string{}, directive, cobra.ShellCompDirectiveNoFileComp)
   249  }
   250  
   251  func TestResourceNameCompletionFuncJointFormNoArgs(t *testing.T) {
   252  	tf, cmd := prepareCompletionTest()
   253  	addPodsToFactory(tf)
   254  
   255  	compFunc := ResourceNameCompletionFunc(tf, "pod")
   256  	comps, directive := compFunc(cmd, []string{}, "pod/b")
   257  	// The <type>/<name> should NOT be supported by this function
   258  	checkCompletion(t, comps, []string{}, directive, cobra.ShellCompDirectiveNoFileComp)
   259  }
   260  
   261  func TestPodResourceNameCompletionFuncNoArgsPodName(t *testing.T) {
   262  	tf, cmd := prepareCompletionTest()
   263  	addPodsToFactory(tf)
   264  
   265  	compFunc := PodResourceNameCompletionFunc(tf)
   266  	comps, directive := compFunc(cmd, []string{}, "b")
   267  	checkCompletion(t, comps, []string{"bar"}, directive, cobra.ShellCompDirectiveNoFileComp)
   268  }
   269  
   270  func TestPodResourceNameCompletionFuncNoArgsResources(t *testing.T) {
   271  	tf, cmd := prepareCompletionTest()
   272  	addPodsToFactory(tf)
   273  
   274  	compFunc := PodResourceNameCompletionFunc(tf)
   275  	comps, directive := compFunc(cmd, []string{}, "d")
   276  	checkCompletion(
   277  		t, comps, []string{"daemonsets/", "deployments/"},
   278  		directive, cobra.ShellCompDirectiveNoFileComp|cobra.ShellCompDirectiveNoSpace)
   279  }
   280  
   281  func TestPodResourceNameCompletionFuncTooManyArgs(t *testing.T) {
   282  	tf, cmd := prepareCompletionTest()
   283  	addPodsToFactory(tf)
   284  
   285  	compFunc := PodResourceNameCompletionFunc(tf)
   286  	comps, directive := compFunc(cmd, []string{"pod-name"}, "")
   287  	checkCompletion(t, comps, []string{}, directive, cobra.ShellCompDirectiveNoFileComp)
   288  }
   289  
   290  func TestPodResourceNameCompletionFuncJointFormNoArgs(t *testing.T) {
   291  	tf, cmd := prepareCompletionTest()
   292  	addPodsToFactory(tf)
   293  
   294  	compFunc := PodResourceNameCompletionFunc(tf)
   295  	comps, directive := compFunc(cmd, []string{}, "pod/b")
   296  	// The <type>/<name> SHOULD be supported by this function
   297  	checkCompletion(t, comps, []string{"pod/bar"}, directive, cobra.ShellCompDirectiveNoFileComp)
   298  }
   299  
   300  func TestPodResourceNameCompletionFuncJointFormTooManyArgs(t *testing.T) {
   301  	tf, cmd := prepareCompletionTest()
   302  	addPodsToFactory(tf)
   303  
   304  	compFunc := PodResourceNameCompletionFunc(tf)
   305  	comps, directive := compFunc(cmd, []string{"pod/name"}, "pod/b")
   306  	checkCompletion(t, comps, []string{}, directive, cobra.ShellCompDirectiveNoFileComp)
   307  }
   308  
   309  func TestPodResourceNameAndContainerCompletionFuncNoArgsPodName(t *testing.T) {
   310  	tf, cmd := prepareCompletionTest()
   311  	addPodsToFactory(tf)
   312  
   313  	compFunc := PodResourceNameAndContainerCompletionFunc(tf)
   314  	comps, directive := compFunc(cmd, []string{}, "b")
   315  	checkCompletion(t, comps, []string{"bar"}, directive, cobra.ShellCompDirectiveNoFileComp)
   316  }
   317  
   318  func TestPodResourceNameAndContainerCompletionFuncNoArgsResources(t *testing.T) {
   319  	tf, cmd := prepareCompletionTest()
   320  	addPodsToFactory(tf)
   321  
   322  	compFunc := PodResourceNameAndContainerCompletionFunc(tf)
   323  	comps, directive := compFunc(cmd, []string{}, "s")
   324  	checkCompletion(
   325  		t, comps, []string{"services/", "statefulsets/"},
   326  		directive, cobra.ShellCompDirectiveNoFileComp|cobra.ShellCompDirectiveNoSpace)
   327  
   328  }
   329  
   330  func TestPodResourceNameAndContainerCompletionFuncTooManyArgs(t *testing.T) {
   331  	tf, cmd := prepareCompletionTest()
   332  	addPodsToFactory(tf)
   333  
   334  	compFunc := PodResourceNameAndContainerCompletionFunc(tf)
   335  	comps, directive := compFunc(cmd, []string{"pod-name", "container-name"}, "")
   336  	checkCompletion(t, comps, []string{}, directive, cobra.ShellCompDirectiveNoFileComp)
   337  }
   338  
   339  func TestPodResourceNameAndContainerCompletionFuncJointFormNoArgs(t *testing.T) {
   340  	tf, cmd := prepareCompletionTest()
   341  	addPodsToFactory(tf)
   342  
   343  	compFunc := PodResourceNameAndContainerCompletionFunc(tf)
   344  	comps, directive := compFunc(cmd, []string{}, "pod/b")
   345  	checkCompletion(t, comps, []string{"pod/bar"}, directive, cobra.ShellCompDirectiveNoFileComp)
   346  }
   347  
   348  func TestPodResourceNameAndContainerCompletionFuncJointFormTooManyArgs(t *testing.T) {
   349  	tf, cmd := prepareCompletionTest()
   350  	addPodsToFactory(tf)
   351  
   352  	compFunc := PodResourceNameAndContainerCompletionFunc(tf)
   353  	comps, directive := compFunc(cmd, []string{"pod/pod-name", "container-name"}, "")
   354  	checkCompletion(t, comps, []string{}, directive, cobra.ShellCompDirectiveNoFileComp)
   355  }
   356  
   357  func setMockFactory(config api.Config) {
   358  	clientConfig := clientcmd.NewDefaultClientConfig(config, nil)
   359  	testFactory := cmdtesting.NewTestFactory().WithClientConfig(clientConfig)
   360  	SetFactoryForCompletion(testFactory)
   361  }
   362  
   363  func prepareCompletionTest() (*cmdtesting.TestFactory, *cobra.Command) {
   364  	tf := cmdtesting.NewTestFactory().WithNamespace("test")
   365  	defer tf.Cleanup()
   366  
   367  	streams, _, _, _ := genericiooptions.NewTestIOStreams()
   368  	cmd := get.NewCmdGet("kubectl", tf, streams)
   369  	return tf, cmd
   370  }
   371  
   372  func addPodsToFactory(tf *cmdtesting.TestFactory) {
   373  	pods, _, _ := cmdtesting.TestData()
   374  	codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
   375  	tf.UnstructuredClient = &fake.RESTClient{
   376  		NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
   377  		Resp:                 &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, pods)},
   378  	}
   379  }
   380  
   381  func checkCompletion(t *testing.T, comps, expectedComps []string, directive, expectedDirective cobra.ShellCompDirective) {
   382  	if e, d := expectedDirective, directive; e != d {
   383  		t.Errorf("expected directive\n%v\nbut got\n%v", e, d)
   384  	}
   385  
   386  	sort.Strings(comps)
   387  	sort.Strings(expectedComps)
   388  
   389  	if len(expectedComps) != len(comps) {
   390  		t.Fatalf("expected completions\n%v\nbut got\n%v", expectedComps, comps)
   391  	}
   392  
   393  	for i := range comps {
   394  		if expectedComps[i] != comps[i] {
   395  			t.Errorf("expected completions\n%v\nbut got\n%v", expectedComps, comps)
   396  			break
   397  		}
   398  	}
   399  }
   400  

View as plain text