...

Source file src/k8s.io/kubectl/pkg/cmd/describe/describe_test.go

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

     1  /*
     2  Copyright 2014 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 describe
    18  
    19  import (
    20  	"fmt"
    21  	"net/http"
    22  	"strings"
    23  	"testing"
    24  
    25  	"k8s.io/apimachinery/pkg/api/meta"
    26  	"k8s.io/cli-runtime/pkg/genericclioptions"
    27  	"k8s.io/cli-runtime/pkg/genericiooptions"
    28  	"k8s.io/cli-runtime/pkg/resource"
    29  	"k8s.io/client-go/rest/fake"
    30  	cmdtesting "k8s.io/kubectl/pkg/cmd/testing"
    31  	"k8s.io/kubectl/pkg/describe"
    32  	"k8s.io/kubectl/pkg/scheme"
    33  )
    34  
    35  // Verifies that schemas that are not in the master tree of Kubernetes can be retrieved via Get.
    36  func TestDescribeUnknownSchemaObject(t *testing.T) {
    37  	d := &testDescriber{Output: "test output"}
    38  	oldFn := describe.DescriberFn
    39  	defer func() {
    40  		describe.DescriberFn = oldFn
    41  	}()
    42  	describe.DescriberFn = d.describerFor
    43  
    44  	tf := cmdtesting.NewTestFactory().WithNamespace("non-default")
    45  	defer tf.Cleanup()
    46  	_, _, codec := cmdtesting.NewExternalScheme()
    47  
    48  	tf.UnstructuredClient = &fake.RESTClient{
    49  		NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
    50  		Resp:                 &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, cmdtesting.NewInternalType("", "", "foo"))},
    51  	}
    52  
    53  	streams, _, buf, _ := genericiooptions.NewTestIOStreams()
    54  
    55  	cmd := NewCmdDescribe("kubectl", tf, streams)
    56  	cmd.Run(cmd, []string{"type", "foo"})
    57  
    58  	if d.Name != "foo" || d.Namespace != "" {
    59  		t.Errorf("unexpected describer: %#v", d)
    60  	}
    61  
    62  	if buf.String() != d.Output {
    63  		t.Errorf("unexpected output: %s", buf.String())
    64  	}
    65  }
    66  
    67  // Verifies that schemas that are not in the master tree of Kubernetes can be retrieved via Get.
    68  func TestDescribeUnknownNamespacedSchemaObject(t *testing.T) {
    69  	d := &testDescriber{Output: "test output"}
    70  	oldFn := describe.DescriberFn
    71  	defer func() {
    72  		describe.DescriberFn = oldFn
    73  	}()
    74  	describe.DescriberFn = d.describerFor
    75  
    76  	tf := cmdtesting.NewTestFactory()
    77  	defer tf.Cleanup()
    78  	_, _, codec := cmdtesting.NewExternalScheme()
    79  
    80  	tf.UnstructuredClient = &fake.RESTClient{
    81  		NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
    82  		Resp:                 &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, cmdtesting.NewInternalNamespacedType("", "", "foo", "non-default"))},
    83  	}
    84  	tf.WithNamespace("non-default")
    85  
    86  	streams, _, buf, _ := genericiooptions.NewTestIOStreams()
    87  
    88  	cmd := NewCmdDescribe("kubectl", tf, streams)
    89  	cmd.Run(cmd, []string{"namespacedtype", "foo"})
    90  
    91  	if d.Name != "foo" || d.Namespace != "non-default" {
    92  		t.Errorf("unexpected describer: %#v", d)
    93  	}
    94  
    95  	if buf.String() != d.Output {
    96  		t.Errorf("unexpected output: %s", buf.String())
    97  	}
    98  }
    99  
   100  func TestDescribeObject(t *testing.T) {
   101  	d := &testDescriber{Output: "test output"}
   102  	oldFn := describe.DescriberFn
   103  	defer func() {
   104  		describe.DescriberFn = oldFn
   105  	}()
   106  	describe.DescriberFn = d.describerFor
   107  
   108  	_, _, rc := cmdtesting.TestData()
   109  	tf := cmdtesting.NewTestFactory().WithNamespace("test")
   110  	defer tf.Cleanup()
   111  	codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
   112  
   113  	tf.UnstructuredClient = &fake.RESTClient{
   114  		NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
   115  		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
   116  			switch p, m := req.URL.Path, req.Method; {
   117  			case p == "/namespaces/test/replicationcontrollers/redis-master" && m == "GET":
   118  				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &rc.Items[0])}, nil
   119  			default:
   120  				t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
   121  				return nil, nil
   122  			}
   123  		}),
   124  	}
   125  
   126  	streams, _, buf, _ := genericiooptions.NewTestIOStreams()
   127  
   128  	cmd := NewCmdDescribe("kubectl", tf, streams)
   129  	cmd.Flags().Set("filename", "../../../testdata/redis-master-controller.yaml")
   130  	cmd.Run(cmd, []string{})
   131  
   132  	if d.Name != "redis-master" || d.Namespace != "test" {
   133  		t.Errorf("unexpected describer: %#v", d)
   134  	}
   135  
   136  	if buf.String() != d.Output {
   137  		t.Errorf("unexpected output: %s", buf.String())
   138  	}
   139  }
   140  
   141  func TestDescribeListObjects(t *testing.T) {
   142  	d := &testDescriber{Output: "test output"}
   143  	oldFn := describe.DescriberFn
   144  	defer func() {
   145  		describe.DescriberFn = oldFn
   146  	}()
   147  	describe.DescriberFn = d.describerFor
   148  
   149  	pods, _, _ := cmdtesting.TestData()
   150  	tf := cmdtesting.NewTestFactory().WithNamespace("test")
   151  	defer tf.Cleanup()
   152  	codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
   153  
   154  	tf.UnstructuredClient = &fake.RESTClient{
   155  		NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
   156  		Resp:                 &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, pods)},
   157  	}
   158  
   159  	streams, _, buf, _ := genericiooptions.NewTestIOStreams()
   160  
   161  	cmd := NewCmdDescribe("kubectl", tf, streams)
   162  	cmd.Run(cmd, []string{"pods"})
   163  	if buf.String() != fmt.Sprintf("%s\n\n%s", d.Output, d.Output) {
   164  		t.Errorf("unexpected output: %s", buf.String())
   165  	}
   166  }
   167  
   168  func TestDescribeObjectShowEvents(t *testing.T) {
   169  	d := &testDescriber{Output: "test output"}
   170  	oldFn := describe.DescriberFn
   171  	defer func() {
   172  		describe.DescriberFn = oldFn
   173  	}()
   174  	describe.DescriberFn = d.describerFor
   175  
   176  	pods, _, _ := cmdtesting.TestData()
   177  	tf := cmdtesting.NewTestFactory().WithNamespace("test")
   178  	defer tf.Cleanup()
   179  	codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
   180  
   181  	tf.UnstructuredClient = &fake.RESTClient{
   182  		NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
   183  		Resp:                 &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, pods)},
   184  	}
   185  
   186  	cmd := NewCmdDescribe("kubectl", tf, genericiooptions.NewTestIOStreamsDiscard())
   187  	cmd.Flags().Set("show-events", "true")
   188  	cmd.Run(cmd, []string{"pods"})
   189  	if d.Settings.ShowEvents != true {
   190  		t.Errorf("ShowEvents = true expected, got ShowEvents = %v", d.Settings.ShowEvents)
   191  	}
   192  }
   193  
   194  func TestDescribeObjectSkipEvents(t *testing.T) {
   195  	d := &testDescriber{Output: "test output"}
   196  	oldFn := describe.DescriberFn
   197  	defer func() {
   198  		describe.DescriberFn = oldFn
   199  	}()
   200  	describe.DescriberFn = d.describerFor
   201  
   202  	pods, _, _ := cmdtesting.TestData()
   203  	tf := cmdtesting.NewTestFactory().WithNamespace("test")
   204  	defer tf.Cleanup()
   205  	codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
   206  
   207  	tf.UnstructuredClient = &fake.RESTClient{
   208  		NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
   209  		Resp:                 &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, pods)},
   210  	}
   211  
   212  	cmd := NewCmdDescribe("kubectl", tf, genericiooptions.NewTestIOStreamsDiscard())
   213  	cmd.Flags().Set("show-events", "false")
   214  	cmd.Run(cmd, []string{"pods"})
   215  	if d.Settings.ShowEvents != false {
   216  		t.Errorf("ShowEvents = false expected, got ShowEvents = %v", d.Settings.ShowEvents)
   217  	}
   218  }
   219  
   220  func TestDescribeObjectChunkSize(t *testing.T) {
   221  	d := &testDescriber{Output: "test output"}
   222  	oldFn := describe.DescriberFn
   223  	defer func() {
   224  		describe.DescriberFn = oldFn
   225  	}()
   226  	describe.DescriberFn = d.describerFor
   227  
   228  	pods, _, _ := cmdtesting.TestData()
   229  	tf := cmdtesting.NewTestFactory().WithNamespace("test")
   230  	defer tf.Cleanup()
   231  	codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
   232  
   233  	tf.UnstructuredClient = &fake.RESTClient{
   234  		NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
   235  		Resp:                 &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, pods)},
   236  	}
   237  
   238  	cmd := NewCmdDescribe("kubectl", tf, genericiooptions.NewTestIOStreamsDiscard())
   239  	cmd.Flags().Set("chunk-size", "100")
   240  	cmd.Run(cmd, []string{"pods"})
   241  	if d.Settings.ChunkSize != 100 {
   242  		t.Errorf("ChunkSize = 100 expected, got ChunkSize = %v", d.Settings.ChunkSize)
   243  	}
   244  }
   245  
   246  func TestDescribeHelpMessage(t *testing.T) {
   247  	tf := cmdtesting.NewTestFactory()
   248  	defer tf.Cleanup()
   249  
   250  	streams, _, buf, _ := genericiooptions.NewTestIOStreams()
   251  
   252  	cmd := NewCmdDescribe("kubectl", tf, streams)
   253  	cmd.SetArgs([]string{"-h"})
   254  	cmd.SetOut(buf)
   255  	cmd.SetErr(buf)
   256  	_, err := cmd.ExecuteC()
   257  
   258  	if err != nil {
   259  		t.Fatalf("Unexpected error: %v", err)
   260  	}
   261  
   262  	got := buf.String()
   263  
   264  	expected := `describe (-f FILENAME | TYPE [NAME_PREFIX | -l label] | TYPE/NAME)`
   265  	if !strings.Contains(got, expected) {
   266  		t.Errorf("Expected to contain: \n %v\nGot:\n %v\n", expected, got)
   267  	}
   268  
   269  	unexpected := `describe (-f FILENAME | TYPE [NAME_PREFIX | -l label] | TYPE/NAME) [flags]`
   270  	if strings.Contains(got, unexpected) {
   271  		t.Errorf("Expected not to contain: \n %v\nGot:\n %v\n", unexpected, got)
   272  	}
   273  }
   274  
   275  func TestDescribeNoResourcesFound(t *testing.T) {
   276  	testNS := "testns"
   277  	testCases := []struct {
   278  		name           string
   279  		flags          map[string]string
   280  		namespace      string
   281  		expectedOutput string
   282  		expectedErr    string
   283  	}{
   284  		{
   285  			name:           "all namespaces",
   286  			flags:          map[string]string{"all-namespaces": "true"},
   287  			expectedOutput: "",
   288  			expectedErr:    "No resources found\n",
   289  		},
   290  		{
   291  			name:           "all in namespace",
   292  			namespace:      testNS,
   293  			expectedOutput: "",
   294  			expectedErr:    "No resources found in " + testNS + " namespace.\n",
   295  		},
   296  	}
   297  	cmdtesting.InitTestErrorHandler(t)
   298  	for _, testCase := range testCases {
   299  		t.Run(testCase.name, func(t *testing.T) {
   300  			pods, _, _ := cmdtesting.EmptyTestData()
   301  			tf := cmdtesting.NewTestFactory().WithNamespace(testNS)
   302  			defer tf.Cleanup()
   303  			codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
   304  
   305  			tf.UnstructuredClient = &fake.RESTClient{
   306  				NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
   307  				Resp:                 &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, pods)},
   308  			}
   309  
   310  			streams, _, buf, errbuf := genericiooptions.NewTestIOStreams()
   311  
   312  			cmd := NewCmdDescribe("kubectl", tf, streams)
   313  			for name, value := range testCase.flags {
   314  				_ = cmd.Flags().Set(name, value)
   315  			}
   316  			cmd.Run(cmd, []string{"pods"})
   317  
   318  			if e, a := testCase.expectedOutput, buf.String(); e != a {
   319  				t.Errorf("Unexpected output:\nExpected:\n%v\nActual:\n%v", e, a)
   320  			}
   321  			if e, a := testCase.expectedErr, errbuf.String(); e != a {
   322  				t.Errorf("Unexpected error:\nExpected:\n%v\nActual:\n%v", e, a)
   323  			}
   324  		})
   325  	}
   326  }
   327  
   328  type testDescriber struct {
   329  	Name, Namespace string
   330  	Settings        describe.DescriberSettings
   331  	Output          string
   332  	Err             error
   333  }
   334  
   335  func (t *testDescriber) Describe(namespace, name string, describerSettings describe.DescriberSettings) (output string, err error) {
   336  	t.Namespace, t.Name = namespace, name
   337  	t.Settings = describerSettings
   338  	return t.Output, t.Err
   339  }
   340  func (t *testDescriber) describerFor(restClientGetter genericclioptions.RESTClientGetter, mapping *meta.RESTMapping) (describe.ResourceDescriber, error) {
   341  	return t, nil
   342  }
   343  

View as plain text