1/*
2Copyright 2014 The Kubernetes Authors.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8    http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17package get
18
19import (
20	"bytes"
21	"encoding/json"
22	encjson "encoding/json"
23	"fmt"
24	"io"
25	"io/ioutil"
26	"net/http"
27	"path/filepath"
28	"reflect"
29	"strings"
30	"testing"
31
32	appsv1 "k8s.io/api/apps/v1"
33	autoscalingv1 "k8s.io/api/autoscaling/v1"
34	batchv1 "k8s.io/api/batch/v1"
35	batchv1beta1 "k8s.io/api/batch/v1beta1"
36	corev1 "k8s.io/api/core/v1"
37	extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
38	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
39	metav1beta1 "k8s.io/apimachinery/pkg/apis/meta/v1beta1"
40	"k8s.io/apimachinery/pkg/runtime"
41	"k8s.io/apimachinery/pkg/runtime/schema"
42	"k8s.io/apimachinery/pkg/runtime/serializer/streaming"
43	"k8s.io/apimachinery/pkg/util/diff"
44	"k8s.io/apimachinery/pkg/watch"
45	"k8s.io/cli-runtime/pkg/genericclioptions"
46	"k8s.io/cli-runtime/pkg/resource"
47	restclient "k8s.io/client-go/rest"
48	"k8s.io/client-go/rest/fake"
49	restclientwatch "k8s.io/client-go/rest/watch"
50	"k8s.io/kube-openapi/pkg/util/proto"
51	cmdtesting "k8s.io/kubectl/pkg/cmd/testing"
52	"k8s.io/kubectl/pkg/scheme"
53	"k8s.io/kubectl/pkg/util/openapi"
54	openapitesting "k8s.io/kubectl/pkg/util/openapi/testing"
55)
56
57var (
58	openapiSchemaPath  = filepath.Join("..", "..", "..", "testdata", "openapi", "swagger.json")
59	grace              = int64(30)
60	enableServiceLinks = corev1.DefaultEnableServiceLinks
61)
62
63func testComponentStatusData() *corev1.ComponentStatusList {
64	good := corev1.ComponentStatus{
65		Conditions: []corev1.ComponentCondition{
66			{Type: corev1.ComponentHealthy, Status: corev1.ConditionTrue, Message: "ok"},
67		},
68		ObjectMeta: metav1.ObjectMeta{Name: "servergood"},
69	}
70
71	bad := corev1.ComponentStatus{
72		Conditions: []corev1.ComponentCondition{
73			{Type: corev1.ComponentHealthy, Status: corev1.ConditionFalse, Message: "", Error: "bad status: 500"},
74		},
75		ObjectMeta: metav1.ObjectMeta{Name: "serverbad"},
76	}
77
78	unknown := corev1.ComponentStatus{
79		Conditions: []corev1.ComponentCondition{
80			{Type: corev1.ComponentHealthy, Status: corev1.ConditionUnknown, Message: "", Error: "fizzbuzz error"},
81		},
82		ObjectMeta: metav1.ObjectMeta{Name: "serverunknown"},
83	}
84
85	return &corev1.ComponentStatusList{
86		Items: []corev1.ComponentStatus{good, bad, unknown},
87	}
88}
89
90// Verifies that schemas that are not in the master tree of Kubernetes can be retrieved via Get.
91func TestGetUnknownSchemaObject(t *testing.T) {
92	t.Skip("This test is completely broken.  The first thing it does is add the object to the scheme!")
93	tf := cmdtesting.NewTestFactory().WithNamespace("test")
94	defer tf.Cleanup()
95	_, _, codec := cmdtesting.NewExternalScheme()
96	tf.OpenAPISchemaFunc = openapitesting.CreateOpenAPISchemaFunc(openapiSchemaPath)
97
98	obj := &cmdtesting.ExternalType{
99		Kind:       "Type",
100		APIVersion: "apitest/unlikelyversion",
101		Name:       "foo",
102	}
103
104	tf.UnstructuredClient = &fake.RESTClient{
105		NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
106		Resp: &http.Response{
107			StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(),
108			Body: cmdtesting.ObjBody(codec, obj),
109		},
110	}
111	tf.ClientConfigVal = cmdtesting.DefaultClientConfig()
112
113	streams, _, buf, _ := genericclioptions.NewTestIOStreams()
114	cmd := NewCmdGet("kubectl", tf, streams)
115	cmd.SetOutput(buf)
116	cmd.Run(cmd, []string{"type", "foo"})
117
118	expected := []runtime.Object{cmdtesting.NewInternalType("", "", "foo")}
119	actual := []runtime.Object{}
120	if len(actual) != len(expected) {
121		t.Fatalf("expected: %#v, but actual: %#v", expected, actual)
122	}
123	t.Logf("actual: %#v", actual[0])
124	for i, obj := range actual {
125		expectedJSON := runtime.EncodeOrDie(codec, expected[i])
126		expectedMap := map[string]interface{}{}
127		if err := encjson.Unmarshal([]byte(expectedJSON), &expectedMap); err != nil {
128			t.Fatal(err)
129		}
130
131		actualJSON := runtime.EncodeOrDie(codec, obj)
132		actualMap := map[string]interface{}{}
133		if err := encjson.Unmarshal([]byte(actualJSON), &actualMap); err != nil {
134			t.Fatal(err)
135		}
136
137		if !reflect.DeepEqual(expectedMap, actualMap) {
138			t.Errorf("expectedMap: %#v, but actualMap: %#v", expectedMap, actualMap)
139		}
140	}
141}
142
143// Verifies that schemas that are not in the master tree of Kubernetes can be retrieved via Get.
144func TestGetSchemaObject(t *testing.T) {
145	tf := cmdtesting.NewTestFactory().WithNamespace("test")
146	defer tf.Cleanup()
147	codec := scheme.Codecs.LegacyCodec(corev1.SchemeGroupVersion)
148	t.Logf("%v", string(runtime.EncodeOrDie(codec, &corev1.ReplicationController{ObjectMeta: metav1.ObjectMeta{Name: "foo"}})))
149
150	tf.UnstructuredClient = &fake.RESTClient{
151		NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
152		Resp:                 &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &corev1.ReplicationController{ObjectMeta: metav1.ObjectMeta{Name: "foo"}})},
153	}
154	tf.ClientConfigVal = cmdtesting.DefaultClientConfig()
155
156	streams, _, buf, _ := genericclioptions.NewTestIOStreams()
157	cmd := NewCmdGet("kubectl", tf, streams)
158	cmd.Run(cmd, []string{"replicationcontrollers", "foo"})
159
160	if !strings.Contains(buf.String(), "foo") {
161		t.Errorf("unexpected output: %s", buf.String())
162	}
163}
164
165func TestGetObjectsWithOpenAPIOutputFormatPresent(t *testing.T) {
166	pods, _, _ := cmdtesting.TestData()
167
168	tf := cmdtesting.NewTestFactory().WithNamespace("test")
169	defer tf.Cleanup()
170	codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
171
172	// overide the openAPISchema function to return custom output
173	// for Pod type.
174	tf.OpenAPISchemaFunc = testOpenAPISchemaData
175	tf.UnstructuredClient = &fake.RESTClient{
176		NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
177		Resp:                 &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &pods.Items[0])},
178	}
179
180	streams, _, buf, _ := genericclioptions.NewTestIOStreams()
181	cmd := NewCmdGet("kubectl", tf, streams)
182	cmd.SetOutput(buf)
183	cmd.Flags().Set(useOpenAPIPrintColumnFlagLabel, "true")
184	cmd.Run(cmd, []string{"pods", "foo"})
185
186	expected := `NAME   RSRC
187foo    10
188`
189	if e, a := expected, buf.String(); e != a {
190		t.Errorf("expected\n%v\ngot\n%v", e, a)
191	}
192}
193
194type FakeResources struct {
195	resources map[schema.GroupVersionKind]proto.Schema
196}
197
198func (f FakeResources) LookupResource(s schema.GroupVersionKind) proto.Schema {
199	return f.resources[s]
200}
201
202var _ openapi.Resources = &FakeResources{}
203
204func testOpenAPISchemaData() (openapi.Resources, error) {
205	return &FakeResources{
206		resources: map[schema.GroupVersionKind]proto.Schema{
207			{
208				Version: "v1",
209				Kind:    "Pod",
210			}: &proto.Primitive{
211				BaseSchema: proto.BaseSchema{
212					Extensions: map[string]interface{}{
213						"x-kubernetes-print-columns": "custom-columns=NAME:.metadata.name,RSRC:.metadata.resourceVersion",
214					},
215				},
216			},
217		},
218	}, nil
219}
220
221func TestGetObjects(t *testing.T) {
222	pods, _, _ := cmdtesting.TestData()
223
224	tf := cmdtesting.NewTestFactory().WithNamespace("test")
225	defer tf.Cleanup()
226	codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
227
228	tf.UnstructuredClient = &fake.RESTClient{
229		NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
230		Resp:                 &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &pods.Items[0])},
231	}
232
233	streams, _, buf, _ := genericclioptions.NewTestIOStreams()
234	cmd := NewCmdGet("kubectl", tf, streams)
235	cmd.SetOutput(buf)
236	cmd.Run(cmd, []string{"pods", "foo"})
237
238	expected := `NAME   AGE
239foo    <unknown>
240`
241	if e, a := expected, buf.String(); e != a {
242		t.Errorf("expected\n%v\ngot\n%v", e, a)
243	}
244}
245
246func TestGetTableObjects(t *testing.T) {
247	pods, _, _ := cmdtesting.TestData()
248
249	tf := cmdtesting.NewTestFactory().WithNamespace("test")
250	defer tf.Cleanup()
251	codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
252
253	tf.UnstructuredClient = &fake.RESTClient{
254		NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
255		Resp:                 &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: podTableObjBody(codec, pods.Items[0])},
256	}
257
258	streams, _, buf, _ := genericclioptions.NewTestIOStreams()
259	cmd := NewCmdGet("kubectl", tf, streams)
260	cmd.SetOutput(buf)
261	cmd.Run(cmd, []string{"pods", "foo"})
262
263	expected := `NAME   READY   STATUS   RESTARTS   AGE
264foo    0/0              0          <unknown>
265`
266	if e, a := expected, buf.String(); e != a {
267		t.Errorf("expected\n%v\ngot\n%v", e, a)
268	}
269}
270
271func TestGetV1TableObjects(t *testing.T) {
272	pods, _, _ := cmdtesting.TestData()
273
274	tf := cmdtesting.NewTestFactory().WithNamespace("test")
275	defer tf.Cleanup()
276	codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
277
278	tf.UnstructuredClient = &fake.RESTClient{
279		NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
280		Resp:                 &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: podV1TableObjBody(codec, pods.Items[0])},
281	}
282
283	streams, _, buf, _ := genericclioptions.NewTestIOStreams()
284	cmd := NewCmdGet("kubectl", tf, streams)
285	cmd.SetOutput(buf)
286	cmd.Run(cmd, []string{"pods", "foo"})
287
288	expected := `NAME   READY   STATUS   RESTARTS   AGE
289foo    0/0              0          <unknown>
290`
291	if e, a := expected, buf.String(); e != a {
292		t.Errorf("expected\n%v\ngot\n%v", e, a)
293	}
294}
295
296func TestGetObjectsShowKind(t *testing.T) {
297	pods, _, _ := cmdtesting.TestData()
298
299	tf := cmdtesting.NewTestFactory().WithNamespace("test")
300	defer tf.Cleanup()
301	codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
302
303	tf.UnstructuredClient = &fake.RESTClient{
304		NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
305		Resp:                 &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &pods.Items[0])},
306	}
307
308	streams, _, buf, _ := genericclioptions.NewTestIOStreams()
309	cmd := NewCmdGet("kubectl", tf, streams)
310	cmd.SetOutput(buf)
311	cmd.Flags().Set("show-kind", "true")
312	cmd.Run(cmd, []string{"pods", "foo"})
313
314	expected := `NAME      AGE
315pod/foo   <unknown>
316`
317	if e, a := expected, buf.String(); e != a {
318		t.Errorf("expected\n%v\ngot\n%v", e, a)
319	}
320}
321
322func TestGetTableObjectsShowKind(t *testing.T) {
323	pods, _, _ := cmdtesting.TestData()
324
325	tf := cmdtesting.NewTestFactory().WithNamespace("test")
326	defer tf.Cleanup()
327	codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
328
329	tf.UnstructuredClient = &fake.RESTClient{
330		NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
331		Resp:                 &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: podTableObjBody(codec, pods.Items[0])},
332	}
333
334	streams, _, buf, _ := genericclioptions.NewTestIOStreams()
335	cmd := NewCmdGet("kubectl", tf, streams)
336	cmd.SetOutput(buf)
337	cmd.Flags().Set("show-kind", "true")
338	cmd.Run(cmd, []string{"pods", "foo"})
339
340	expected := `NAME      READY   STATUS   RESTARTS   AGE
341pod/foo   0/0              0          <unknown>
342`
343	if e, a := expected, buf.String(); e != a {
344		t.Errorf("expected\n%v\ngot\n%v", e, a)
345	}
346}
347
348func TestGetMultipleResourceTypesShowKinds(t *testing.T) {
349	pods, svcs, _ := cmdtesting.TestData()
350
351	tf := cmdtesting.NewTestFactory().WithNamespace("test")
352	defer tf.Cleanup()
353
354	codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
355	tf.UnstructuredClient = &fake.RESTClient{
356		NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
357		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
358			switch p, m := req.URL.Path, req.Method; {
359			case p == "/namespaces/test/pods" && m == "GET":
360				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, pods)}, nil
361			case p == "/namespaces/test/replicationcontrollers" && m == "GET":
362				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &corev1.ReplicationControllerList{})}, nil
363			case p == "/namespaces/test/services" && m == "GET":
364				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, svcs)}, nil
365			case p == "/namespaces/test/statefulsets" && m == "GET":
366				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &appsv1.StatefulSetList{})}, nil
367			case p == "/namespaces/test/horizontalpodautoscalers" && m == "GET":
368				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &autoscalingv1.HorizontalPodAutoscalerList{})}, nil
369			case p == "/namespaces/test/jobs" && m == "GET":
370				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &batchv1.JobList{})}, nil
371			case p == "/namespaces/test/cronjobs" && m == "GET":
372				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &batchv1beta1.CronJobList{})}, nil
373			case p == "/namespaces/test/daemonsets" && m == "GET":
374				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &appsv1.DaemonSetList{})}, nil
375			case p == "/namespaces/test/deployments" && m == "GET":
376				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &extensionsv1beta1.DeploymentList{})}, nil
377			case p == "/namespaces/test/replicasets" && m == "GET":
378				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &extensionsv1beta1.ReplicaSetList{})}, nil
379
380			default:
381				t.Fatalf("request url: %#v,and request: %#v", req.URL, req)
382				return nil, nil
383			}
384		}),
385	}
386
387	streams, _, buf, bufErr := genericclioptions.NewTestIOStreams()
388	cmd := NewCmdGet("kubectl", tf, streams)
389	cmd.SetOutput(buf)
390	cmd.Run(cmd, []string{"all"})
391
392	expected := `NAME      AGE
393pod/foo   <unknown>
394pod/bar   <unknown>
395
396NAME          AGE
397service/baz   <unknown>
398`
399	if e, a := expected, buf.String(); e != a {
400		t.Errorf("expected\n%v\ngot\n%v", e, a)
401	}
402
403	// The error out should be empty
404	if e, a := "", bufErr.String(); e != a {
405		t.Errorf("expected\n%v\ngot\n%v", e, a)
406	}
407}
408
409func TestGetMultipleTableResourceTypesShowKinds(t *testing.T) {
410	pods, svcs, _ := cmdtesting.TestData()
411
412	tf := cmdtesting.NewTestFactory().WithNamespace("test")
413	defer tf.Cleanup()
414
415	codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
416	tf.UnstructuredClient = &fake.RESTClient{
417		NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
418		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
419			switch p, m := req.URL.Path, req.Method; {
420			case p == "/namespaces/test/pods" && m == "GET":
421				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: podTableObjBody(codec, pods.Items...)}, nil
422			case p == "/namespaces/test/replicationcontrollers" && m == "GET":
423				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &corev1.ReplicationControllerList{})}, nil
424			case p == "/namespaces/test/services" && m == "GET":
425				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: serviceTableObjBody(codec, svcs.Items...)}, nil
426			case p == "/namespaces/test/statefulsets" && m == "GET":
427				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &appsv1.StatefulSetList{})}, nil
428			case p == "/namespaces/test/horizontalpodautoscalers" && m == "GET":
429				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &autoscalingv1.HorizontalPodAutoscalerList{})}, nil
430			case p == "/namespaces/test/jobs" && m == "GET":
431				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &batchv1.JobList{})}, nil
432			case p == "/namespaces/test/cronjobs" && m == "GET":
433				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &batchv1beta1.CronJobList{})}, nil
434			case p == "/namespaces/test/daemonsets" && m == "GET":
435				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &appsv1.DaemonSetList{})}, nil
436			case p == "/namespaces/test/deployments" && m == "GET":
437				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &extensionsv1beta1.DeploymentList{})}, nil
438			case p == "/namespaces/test/replicasets" && m == "GET":
439				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &extensionsv1beta1.ReplicaSetList{})}, nil
440
441			default:
442				t.Fatalf("request url: %#v,and request: %#v", req.URL, req)
443				return nil, nil
444			}
445		}),
446	}
447
448	streams, _, buf, bufErr := genericclioptions.NewTestIOStreams()
449	cmd := NewCmdGet("kubectl", tf, streams)
450	cmd.SetOutput(buf)
451	cmd.Run(cmd, []string{"all"})
452
453	expected := `NAME      READY   STATUS   RESTARTS   AGE
454pod/foo   0/0              0          <unknown>
455pod/bar   0/0              0          <unknown>
456
457NAME          TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
458service/baz   ClusterIP   <none>       <none>        <none>    <unknown>
459`
460	if e, a := expected, buf.String(); e != a {
461		t.Errorf("expected\n%v\ngot\n%v", e, a)
462	}
463
464	// The error out should be empty
465	if e, a := "", bufErr.String(); e != a {
466		t.Errorf("expected\n%v\ngot\n%v", e, a)
467	}
468}
469
470func TestNoBlankLinesForGetMultipleTableResource(t *testing.T) {
471	pods, svcs, _ := cmdtesting.TestData()
472
473	tf := cmdtesting.NewTestFactory().WithNamespace("test")
474	defer tf.Cleanup()
475
476	codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
477	tf.UnstructuredClient = &fake.RESTClient{
478		NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
479		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
480			switch p, m := req.URL.Path, req.Method; {
481			case p == "/namespaces/test/pods" && m == "GET":
482				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: podTableObjBody(codec, pods.Items...)}, nil
483			case p == "/namespaces/test/replicationcontrollers" && m == "GET":
484				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: emptyTableObjBody(codec)}, nil
485			case p == "/namespaces/test/services" && m == "GET":
486				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: serviceTableObjBody(codec, svcs.Items...)}, nil
487			case p == "/namespaces/test/statefulsets" && m == "GET":
488				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: emptyTableObjBody(codec)}, nil
489			case p == "/namespaces/test/horizontalpodautoscalers" && m == "GET":
490				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: emptyTableObjBody(codec)}, nil
491			case p == "/namespaces/test/jobs" && m == "GET":
492				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: emptyTableObjBody(codec)}, nil
493			case p == "/namespaces/test/cronjobs" && m == "GET":
494				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: emptyTableObjBody(codec)}, nil
495			case p == "/namespaces/test/daemonsets" && m == "GET":
496				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: emptyTableObjBody(codec)}, nil
497			case p == "/namespaces/test/deployments" && m == "GET":
498				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: emptyTableObjBody(codec)}, nil
499			case p == "/namespaces/test/replicasets" && m == "GET":
500				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: emptyTableObjBody(codec)}, nil
501
502			default:
503				t.Fatalf("request url: %#v,and request: %#v", req.URL, req)
504				return nil, nil
505			}
506		}),
507	}
508
509	streams, _, buf, bufErr := genericclioptions.NewTestIOStreams()
510	cmd := NewCmdGet("kubectl", tf, streams)
511	cmd.SetOutput(buf)
512
513	expected := `NAME      READY   STATUS   RESTARTS   AGE
514pod/foo   0/0              0          <unknown>
515pod/bar   0/0              0          <unknown>
516
517NAME          TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
518service/baz   ClusterIP   <none>       <none>        <none>    <unknown>
519`
520	for _, cmdArgs := range [][]string{
521		{"pods,services,jobs"},
522		{"deployments,pods,statefulsets,services,jobs"},
523		{"all"},
524	} {
525		cmd.Run(cmd, cmdArgs)
526
527		if e, a := expected, buf.String(); e != a {
528			t.Errorf("[kubectl get %v] expected\n%v\ngot\n%v", cmdArgs, e, a)
529		}
530
531		// The error out should be empty
532		if e, a := "", bufErr.String(); e != a {
533			t.Errorf("[kubectl get %v] expected\n%v\ngot\n%v", cmdArgs, e, a)
534		}
535
536		buf.Reset()
537		bufErr.Reset()
538	}
539}
540
541func TestNoBlankLinesForGetAll(t *testing.T) {
542	tf := cmdtesting.NewTestFactory().WithNamespace("test")
543	defer tf.Cleanup()
544
545	codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
546	tf.UnstructuredClient = &fake.RESTClient{
547		NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
548		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
549			switch p, m := req.URL.Path, req.Method; {
550			case p == "/namespaces/test/pods" && m == "GET":
551				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: emptyTableObjBody(codec)}, nil
552			case p == "/namespaces/test/replicationcontrollers" && m == "GET":
553				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: emptyTableObjBody(codec)}, nil
554			case p == "/namespaces/test/services" && m == "GET":
555				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: emptyTableObjBody(codec)}, nil
556			case p == "/namespaces/test/statefulsets" && m == "GET":
557				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: emptyTableObjBody(codec)}, nil
558			case p == "/namespaces/test/horizontalpodautoscalers" && m == "GET":
559				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: emptyTableObjBody(codec)}, nil
560			case p == "/namespaces/test/jobs" && m == "GET":
561				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: emptyTableObjBody(codec)}, nil
562			case p == "/namespaces/test/cronjobs" && m == "GET":
563				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: emptyTableObjBody(codec)}, nil
564			case p == "/namespaces/test/daemonsets" && m == "GET":
565				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: emptyTableObjBody(codec)}, nil
566			case p == "/namespaces/test/deployments" && m == "GET":
567				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: emptyTableObjBody(codec)}, nil
568			case p == "/namespaces/test/replicasets" && m == "GET":
569				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: emptyTableObjBody(codec)}, nil
570
571			default:
572				t.Fatalf("request url: %#v,and request: %#v", req.URL, req)
573				return nil, nil
574			}
575		}),
576	}
577
578	streams, _, buf, errbuf := genericclioptions.NewTestIOStreams()
579	cmd := NewCmdGet("kubectl", tf, streams)
580	cmd.SetOutput(buf)
581	cmd.Run(cmd, []string{"all"})
582
583	expected := ``
584	if e, a := expected, buf.String(); e != a {
585		t.Errorf("expected\n%v\ngot\n%v", e, a)
586	}
587	expectedErr := `No resources found in test namespace.
588`
589	if e, a := expectedErr, errbuf.String(); e != a {
590		t.Errorf("expectedErr\n%v\ngot\n%v", e, a)
591	}
592}
593
594func TestGetObjectsShowLabels(t *testing.T) {
595	pods, _, _ := cmdtesting.TestData()
596
597	tf := cmdtesting.NewTestFactory().WithNamespace("test")
598	defer tf.Cleanup()
599	codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
600
601	tf.UnstructuredClient = &fake.RESTClient{
602		NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
603		Resp:                 &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &pods.Items[0])},
604	}
605
606	streams, _, buf, _ := genericclioptions.NewTestIOStreams()
607	cmd := NewCmdGet("kubectl", tf, streams)
608	cmd.SetOutput(buf)
609	cmd.Flags().Set("show-labels", "true")
610	cmd.Run(cmd, []string{"pods", "foo"})
611
612	expected := `NAME   AGE         LABELS
613foo    <unknown>   <none>
614`
615	if e, a := expected, buf.String(); e != a {
616		t.Errorf("expected\n%v\ngot\n%v", e, a)
617	}
618}
619
620func TestGetTableObjectsShowLabels(t *testing.T) {
621	pods, _, _ := cmdtesting.TestData()
622
623	tf := cmdtesting.NewTestFactory().WithNamespace("test")
624	defer tf.Cleanup()
625	codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
626
627	tf.UnstructuredClient = &fake.RESTClient{
628		NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
629		Resp:                 &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: podTableObjBody(codec, pods.Items[0])},
630	}
631
632	streams, _, buf, _ := genericclioptions.NewTestIOStreams()
633	cmd := NewCmdGet("kubectl", tf, streams)
634	cmd.SetOutput(buf)
635	cmd.Flags().Set("show-labels", "true")
636	cmd.Run(cmd, []string{"pods", "foo"})
637
638	expected := `NAME   READY   STATUS   RESTARTS   AGE         LABELS
639foo    0/0              0          <unknown>   <none>
640`
641	if e, a := expected, buf.String(); e != a {
642		t.Errorf("expected\n%v\ngot\n%v", e, a)
643	}
644}
645
646func TestGetEmptyTable(t *testing.T) {
647	tf := cmdtesting.NewTestFactory().WithNamespace("test")
648	defer tf.Cleanup()
649
650	emptyTable := ioutil.NopCloser(bytes.NewBufferString(`{
651"kind":"Table",
652"apiVersion":"meta.k8s.io/v1beta1",
653"metadata":{
654	"selfLink":"/api/v1/namespaces/default/pods",
655	"resourceVersion":"346"
656},
657"columnDefinitions":[
658	{"name":"Name","type":"string","format":"name","description":"the name","priority":0}
659],
660"rows":[]
661}`))
662
663	tf.UnstructuredClient = &fake.RESTClient{
664		NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
665		Resp:                 &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: emptyTable},
666	}
667
668	streams, _, buf, errbuf := genericclioptions.NewTestIOStreams()
669	cmd := NewCmdGet("kubectl", tf, streams)
670	cmd.SetOutput(buf)
671	cmd.Run(cmd, []string{"pods"})
672
673	expected := ``
674	if e, a := expected, buf.String(); e != a {
675		t.Errorf("expected\n%v\ngot\n%v", e, a)
676	}
677	expectedErr := `No resources found in test namespace.
678`
679	if e, a := expectedErr, errbuf.String(); e != a {
680		t.Errorf("expectedErr\n%v\ngot\n%v", e, a)
681	}
682}
683
684func TestGetObjectIgnoreNotFound(t *testing.T) {
685	cmdtesting.InitTestErrorHandler(t)
686
687	ns := &corev1.NamespaceList{
688		ListMeta: metav1.ListMeta{
689			ResourceVersion: "1",
690		},
691		Items: []corev1.Namespace{
692			{
693				ObjectMeta: metav1.ObjectMeta{Name: "testns", Namespace: "test", ResourceVersion: "11"},
694				Spec:       corev1.NamespaceSpec{},
695			},
696		},
697	}
698
699	tf := cmdtesting.NewTestFactory().WithNamespace("test")
700	defer tf.Cleanup()
701	codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
702
703	tf.UnstructuredClient = &fake.RESTClient{
704		NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
705		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
706			switch p, m := req.URL.Path, req.Method; {
707			case p == "/namespaces/test/pods/nonexistentpod" && m == "GET":
708				return &http.Response{StatusCode: http.StatusNotFound, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.StringBody("")}, nil
709			case p == "/api/v1/namespaces/test" && m == "GET":
710				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &ns.Items[0])}, nil
711			default:
712				t.Fatalf("request url: %#v,and request: %#v", req.URL, req)
713				return nil, nil
714			}
715		}),
716	}
717
718	streams, _, buf, _ := genericclioptions.NewTestIOStreams()
719	cmd := NewCmdGet("kubectl", tf, streams)
720	cmd.SetOutput(buf)
721	cmd.Flags().Set("ignore-not-found", "true")
722	cmd.Flags().Set("output", "yaml")
723	cmd.Run(cmd, []string{"pods", "nonexistentpod"})
724
725	if buf.String() != "" {
726		t.Errorf("unexpected output: %s", buf.String())
727	}
728}
729
730func TestEmptyResult(t *testing.T) {
731	cmdtesting.InitTestErrorHandler(t)
732
733	tf := cmdtesting.NewTestFactory().WithNamespace("test")
734	defer tf.Cleanup()
735	codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
736
737	tf.UnstructuredClient = &fake.RESTClient{
738		NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
739		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
740			return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &corev1.PodList{})}, nil
741		}),
742	}
743
744	streams, _, _, errbuf := genericclioptions.NewTestIOStreams()
745	cmd := NewCmdGet("kubectl", tf, streams)
746	// we're assuming that an empty file is being passed from stdin
747	cmd.Flags().Set("filename", "-")
748	cmd.Run(cmd, []string{})
749
750	if !strings.Contains(errbuf.String(), "No resources found") {
751		t.Errorf("unexpected output: %q", errbuf.String())
752	}
753}
754
755func TestEmptyResultJSON(t *testing.T) {
756	cmdtesting.InitTestErrorHandler(t)
757
758	tf := cmdtesting.NewTestFactory().WithNamespace("test")
759	defer tf.Cleanup()
760	codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
761
762	tf.UnstructuredClient = &fake.RESTClient{
763		NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
764		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
765			return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &corev1.PodList{})}, nil
766		}),
767	}
768
769	streams, _, outbuf, errbuf := genericclioptions.NewTestIOStreams()
770	cmd := NewCmdGet("kubectl", tf, streams)
771	// we're assuming that an empty file is being passed from stdin
772	cmd.Flags().Set("filename", "-")
773	cmd.Flags().Set("output", "json")
774	cmd.Run(cmd, []string{})
775
776	if errbuf.Len() > 0 {
777		t.Errorf("unexpected error: %q", errbuf.String())
778	}
779	if !strings.Contains(outbuf.String(), `"items": []`) {
780		t.Errorf("unexpected output: %q", outbuf.String())
781	}
782}
783
784func TestGetSortedObjects(t *testing.T) {
785	pods := &corev1.PodList{
786		ListMeta: metav1.ListMeta{
787			ResourceVersion: "15",
788		},
789		Items: []corev1.Pod{
790			{
791				ObjectMeta: metav1.ObjectMeta{Name: "c", Namespace: "test", ResourceVersion: "10"},
792				Spec: corev1.PodSpec{
793					RestartPolicy:                 corev1.RestartPolicyAlways,
794					DNSPolicy:                     corev1.DNSClusterFirst,
795					TerminationGracePeriodSeconds: &grace,
796					SecurityContext:               &corev1.PodSecurityContext{},
797					EnableServiceLinks:            &enableServiceLinks,
798				},
799			},
800			{
801				ObjectMeta: metav1.ObjectMeta{Name: "b", Namespace: "test", ResourceVersion: "11"},
802				Spec: corev1.PodSpec{
803					RestartPolicy:                 corev1.RestartPolicyAlways,
804					DNSPolicy:                     corev1.DNSClusterFirst,
805					TerminationGracePeriodSeconds: &grace,
806					SecurityContext:               &corev1.PodSecurityContext{},
807					EnableServiceLinks:            &enableServiceLinks,
808				},
809			},
810			{
811				ObjectMeta: metav1.ObjectMeta{Name: "a", Namespace: "test", ResourceVersion: "9"},
812				Spec: corev1.PodSpec{
813					RestartPolicy:                 corev1.RestartPolicyAlways,
814					DNSPolicy:                     corev1.DNSClusterFirst,
815					TerminationGracePeriodSeconds: &grace,
816					SecurityContext:               &corev1.PodSecurityContext{},
817					EnableServiceLinks:            &enableServiceLinks,
818				},
819			},
820		},
821	}
822
823	tf := cmdtesting.NewTestFactory().WithNamespace("test")
824	defer tf.Cleanup()
825	codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
826
827	tf.UnstructuredClient = &fake.RESTClient{
828		NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
829		Resp:                 &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, pods)},
830	}
831	tf.ClientConfigVal = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: &corev1.SchemeGroupVersion}}
832
833	streams, _, buf, _ := genericclioptions.NewTestIOStreams()
834	cmd := NewCmdGet("kubectl", tf, streams)
835	cmd.SetOutput(buf)
836
837	// sorting with metedata.name
838	cmd.Flags().Set("sort-by", ".metadata.name")
839	cmd.Run(cmd, []string{"pods"})
840
841	expected := `NAME   AGE
842a      <unknown>
843b      <unknown>
844c      <unknown>
845`
846	if e, a := expected, buf.String(); e != a {
847		t.Errorf("expected\n%v\ngot\n%v", e, a)
848	}
849}
850
851func TestGetSortedObjectsUnstructuredTable(t *testing.T) {
852	unstructuredMap, err := runtime.DefaultUnstructuredConverter.ToUnstructured(sortTestTableData()[0])
853	if err != nil {
854		t.Fatal(err)
855	}
856	unstructuredBytes, err := encjson.MarshalIndent(unstructuredMap, "", "  ")
857	if err != nil {
858		t.Fatal(err)
859	}
860	// t.Log(string(unstructuredBytes))
861	body := ioutil.NopCloser(bytes.NewReader(unstructuredBytes))
862
863	tf := cmdtesting.NewTestFactory().WithNamespace("test")
864	defer tf.Cleanup()
865
866	tf.UnstructuredClient = &fake.RESTClient{
867		NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
868		Resp:                 &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: body},
869	}
870	tf.ClientConfigVal = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: &corev1.SchemeGroupVersion}}
871
872	streams, _, buf, _ := genericclioptions.NewTestIOStreams()
873	cmd := NewCmdGet("kubectl", tf, streams)
874	cmd.SetOutput(buf)
875
876	// sorting with metedata.name
877	cmd.Flags().Set("sort-by", ".metadata.name")
878	cmd.Run(cmd, []string{"pods"})
879
880	expected := `NAME   CUSTOM
881a      custom-a
882b      custom-b
883c      custom-c
884`
885	if e, a := expected, buf.String(); e != a {
886		t.Errorf("expected\n%v\ngot\n%v", e, a)
887	}
888}
889
890func sortTestData() []runtime.Object {
891	return []runtime.Object{
892		&corev1.Pod{
893			TypeMeta:   metav1.TypeMeta{APIVersion: "v1", Kind: "Pod"},
894			ObjectMeta: metav1.ObjectMeta{Name: "c", Namespace: "test", ResourceVersion: "10"},
895			Spec: corev1.PodSpec{
896				RestartPolicy:                 corev1.RestartPolicyAlways,
897				DNSPolicy:                     corev1.DNSClusterFirst,
898				TerminationGracePeriodSeconds: &grace,
899				SecurityContext:               &corev1.PodSecurityContext{},
900				EnableServiceLinks:            &enableServiceLinks,
901			},
902		},
903		&corev1.Pod{
904			TypeMeta:   metav1.TypeMeta{APIVersion: "v1", Kind: "Pod"},
905			ObjectMeta: metav1.ObjectMeta{Name: "b", Namespace: "test", ResourceVersion: "11"},
906			Spec: corev1.PodSpec{
907				RestartPolicy:                 corev1.RestartPolicyAlways,
908				DNSPolicy:                     corev1.DNSClusterFirst,
909				TerminationGracePeriodSeconds: &grace,
910				SecurityContext:               &corev1.PodSecurityContext{},
911				EnableServiceLinks:            &enableServiceLinks,
912			},
913		},
914		&corev1.Pod{
915			TypeMeta:   metav1.TypeMeta{APIVersion: "v1", Kind: "Pod"},
916			ObjectMeta: metav1.ObjectMeta{Name: "a", Namespace: "test", ResourceVersion: "9"},
917			Spec: corev1.PodSpec{
918				RestartPolicy:                 corev1.RestartPolicyAlways,
919				DNSPolicy:                     corev1.DNSClusterFirst,
920				TerminationGracePeriodSeconds: &grace,
921				SecurityContext:               &corev1.PodSecurityContext{},
922				EnableServiceLinks:            &enableServiceLinks,
923			},
924		},
925	}
926}
927
928func sortTestTableData() []runtime.Object {
929	return []runtime.Object{
930		&metav1beta1.Table{
931			TypeMeta: metav1.TypeMeta{APIVersion: "meta.k8s.io/v1beta1", Kind: "Table"},
932			ColumnDefinitions: []metav1beta1.TableColumnDefinition{
933				{Name: "NAME", Type: "string", Format: "name"},
934				{Name: "CUSTOM", Type: "string", Format: ""},
935			},
936			Rows: []metav1beta1.TableRow{
937				{
938					Cells: []interface{}{"c", "custom-c"},
939					Object: runtime.RawExtension{
940						Object: &corev1.Pod{
941							TypeMeta:   metav1.TypeMeta{APIVersion: "v1", Kind: "Pod"},
942							ObjectMeta: metav1.ObjectMeta{Name: "c", Namespace: "test", ResourceVersion: "10"},
943							Spec: corev1.PodSpec{
944								RestartPolicy:                 corev1.RestartPolicyAlways,
945								DNSPolicy:                     corev1.DNSClusterFirst,
946								TerminationGracePeriodSeconds: &grace,
947								SecurityContext:               &corev1.PodSecurityContext{},
948								EnableServiceLinks:            &enableServiceLinks,
949							},
950						},
951					},
952				},
953				{
954					Cells: []interface{}{"b", "custom-b"},
955					Object: runtime.RawExtension{
956						Object: &corev1.Pod{
957							TypeMeta:   metav1.TypeMeta{APIVersion: "v1", Kind: "Pod"},
958							ObjectMeta: metav1.ObjectMeta{Name: "b", Namespace: "test", ResourceVersion: "11"},
959							Spec: corev1.PodSpec{
960								RestartPolicy:                 corev1.RestartPolicyAlways,
961								DNSPolicy:                     corev1.DNSClusterFirst,
962								TerminationGracePeriodSeconds: &grace,
963								SecurityContext:               &corev1.PodSecurityContext{},
964								EnableServiceLinks:            &enableServiceLinks,
965							},
966						},
967					},
968				},
969				{
970					Cells: []interface{}{"a", "custom-a"},
971					Object: runtime.RawExtension{
972						Object: &corev1.Pod{
973							TypeMeta:   metav1.TypeMeta{APIVersion: "v1", Kind: "Pod"},
974							ObjectMeta: metav1.ObjectMeta{Name: "a", Namespace: "test", ResourceVersion: "9"},
975							Spec: corev1.PodSpec{
976								RestartPolicy:                 corev1.RestartPolicyAlways,
977								DNSPolicy:                     corev1.DNSClusterFirst,
978								TerminationGracePeriodSeconds: &grace,
979								SecurityContext:               &corev1.PodSecurityContext{},
980								EnableServiceLinks:            &enableServiceLinks,
981							},
982						},
983					},
984				},
985			},
986		},
987	}
988}
989
990func TestRuntimeSorter(t *testing.T) {
991	tests := []struct {
992		name        string
993		field       string
994		objs        []runtime.Object
995		op          func(sorter *RuntimeSorter, objs []runtime.Object, out io.Writer) error
996		expect      string
997		expectError string
998	}{
999		{
1000			name:  "ensure sorter works with an empty object list",
1001			field: "metadata.name",
1002			objs:  []runtime.Object{},
1003			op: func(sorter *RuntimeSorter, objs []runtime.Object, out io.Writer) error {
1004				return nil
1005			},
1006			expect: "",
1007		},
1008		{
1009			name:  "ensure sorter returns original position",
1010			field: "metadata.name",
1011			objs:  sortTestData(),
1012			op: func(sorter *RuntimeSorter, objs []runtime.Object, out io.Writer) error {
1013				for idx := range objs {
1014					p := sorter.OriginalPosition(idx)
1015					fmt.Fprintf(out, "%v,", p)
1016				}
1017				return nil
1018			},
1019			expect: "2,1,0,",
1020		},
1021		{
1022			name:  "ensure sorter handles table object position",
1023			field: "metadata.name",
1024			objs:  sortTestTableData(),
1025			op: func(sorter *RuntimeSorter, objs []runtime.Object, out io.Writer) error {
1026				for idx := range objs {
1027					p := sorter.OriginalPosition(idx)
1028					fmt.Fprintf(out, "%v,", p)
1029				}
1030				return nil
1031			},
1032			expect: "0,",
1033		},
1034		{
1035			name:  "ensure sorter sorts table objects",
1036			field: "metadata.name",
1037			objs:  sortTestData(),
1038			op: func(sorter *RuntimeSorter, objs []runtime.Object, out io.Writer) error {
1039				for _, o := range objs {
1040					fmt.Fprintf(out, "%s,", o.(*corev1.Pod).Name)
1041				}
1042				return nil
1043			},
1044			expect: "a,b,c,",
1045		},
1046		{
1047			name:        "ensure sorter rejects mixed Table + non-Table object lists",
1048			field:       "metadata.name",
1049			objs:        append(sortTestData(), sortTestTableData()...),
1050			op:          func(sorter *RuntimeSorter, objs []runtime.Object, out io.Writer) error { return nil },
1051			expectError: "sorting is not supported on mixed Table",
1052		},
1053		{
1054			name:        "ensure sorter errors out on invalid jsonpath",
1055			field:       "metadata.unknown",
1056			objs:        sortTestData(),
1057			op:          func(sorter *RuntimeSorter, objs []runtime.Object, out io.Writer) error { return nil },
1058			expectError: "couldn't find any field with path",
1059		},
1060	}
1061
1062	for _, tc := range tests {
1063		t.Run(tc.name, func(t *testing.T) {
1064			sorter := NewRuntimeSorter(tc.objs, tc.field)
1065			if err := sorter.Sort(); err != nil {
1066				if len(tc.expectError) > 0 && strings.Contains(err.Error(), tc.expectError) {
1067					return
1068				}
1069
1070				if len(tc.expectError) > 0 {
1071					t.Fatalf("unexpected error: expecting %s, but got %s", tc.expectError, err)
1072				}
1073
1074				t.Fatalf("unexpected error: %v", err)
1075			}
1076
1077			out := bytes.NewBuffer([]byte{})
1078			err := tc.op(sorter, tc.objs, out)
1079			if err != nil {
1080				t.Fatalf("unexpected error: %v", err)
1081			}
1082
1083			if tc.expect != out.String() {
1084				t.Fatalf("unexpected output: expecting %s, but got %s", tc.expect, out.String())
1085			}
1086
1087		})
1088	}
1089
1090}
1091
1092func TestGetObjectsIdentifiedByFile(t *testing.T) {
1093	pods, _, _ := cmdtesting.TestData()
1094
1095	tf := cmdtesting.NewTestFactory().WithNamespace("test")
1096	defer tf.Cleanup()
1097	codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
1098
1099	tf.UnstructuredClient = &fake.RESTClient{
1100		NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
1101		Resp:                 &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &pods.Items[0])},
1102	}
1103
1104	streams, _, buf, _ := genericclioptions.NewTestIOStreams()
1105	cmd := NewCmdGet("kubectl", tf, streams)
1106	cmd.SetOutput(buf)
1107	cmd.Flags().Set("filename", "../../../testdata/controller.yaml")
1108	cmd.Run(cmd, []string{})
1109
1110	expected := `NAME   AGE
1111foo    <unknown>
1112`
1113	if e, a := expected, buf.String(); e != a {
1114		t.Errorf("expected\n%v\ngot\n%v", e, a)
1115	}
1116}
1117
1118func TestGetTableObjectsIdentifiedByFile(t *testing.T) {
1119	pods, _, _ := cmdtesting.TestData()
1120
1121	tf := cmdtesting.NewTestFactory().WithNamespace("test")
1122	defer tf.Cleanup()
1123	codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
1124
1125	tf.UnstructuredClient = &fake.RESTClient{
1126		NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
1127		Resp:                 &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: podTableObjBody(codec, pods.Items[0])},
1128	}
1129
1130	streams, _, buf, _ := genericclioptions.NewTestIOStreams()
1131	cmd := NewCmdGet("kubectl", tf, streams)
1132	cmd.SetOutput(buf)
1133	cmd.Flags().Set("filename", "../../../testdata/controller.yaml")
1134	cmd.Run(cmd, []string{})
1135
1136	expected := `NAME   READY   STATUS   RESTARTS   AGE
1137foo    0/0              0          <unknown>
1138`
1139	if e, a := expected, buf.String(); e != a {
1140		t.Errorf("expected\n%v\ngot\n%v", e, a)
1141	}
1142}
1143
1144func TestGetListObjects(t *testing.T) {
1145	pods, _, _ := cmdtesting.TestData()
1146
1147	tf := cmdtesting.NewTestFactory().WithNamespace("test")
1148	defer tf.Cleanup()
1149	codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
1150
1151	tf.UnstructuredClient = &fake.RESTClient{
1152		NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
1153		Resp:                 &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, pods)},
1154	}
1155
1156	streams, _, buf, _ := genericclioptions.NewTestIOStreams()
1157	cmd := NewCmdGet("kubectl", tf, streams)
1158	cmd.SetOutput(buf)
1159	cmd.Run(cmd, []string{"pods"})
1160
1161	expected := `NAME   AGE
1162foo    <unknown>
1163bar    <unknown>
1164`
1165	if e, a := expected, buf.String(); e != a {
1166		t.Errorf("expected\n%v\ngot\n%v", e, a)
1167	}
1168}
1169
1170func TestGetListTableObjects(t *testing.T) {
1171	pods, _, _ := cmdtesting.TestData()
1172
1173	tf := cmdtesting.NewTestFactory().WithNamespace("test")
1174	defer tf.Cleanup()
1175	codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
1176
1177	tf.UnstructuredClient = &fake.RESTClient{
1178		NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
1179		Resp:                 &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: podTableObjBody(codec, pods.Items...)},
1180	}
1181
1182	streams, _, buf, _ := genericclioptions.NewTestIOStreams()
1183	cmd := NewCmdGet("kubectl", tf, streams)
1184	cmd.SetOutput(buf)
1185	cmd.Run(cmd, []string{"pods"})
1186
1187	expected := `NAME   READY   STATUS   RESTARTS   AGE
1188foo    0/0              0          <unknown>
1189bar    0/0              0          <unknown>
1190`
1191	if e, a := expected, buf.String(); e != a {
1192		t.Errorf("expected\n%v\ngot\n%v", e, a)
1193	}
1194}
1195
1196func TestGetListComponentStatus(t *testing.T) {
1197	statuses := testComponentStatusData()
1198
1199	tf := cmdtesting.NewTestFactory().WithNamespace("test")
1200	defer tf.Cleanup()
1201	codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
1202
1203	tf.UnstructuredClient = &fake.RESTClient{
1204		NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
1205		Resp:                 &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: componentStatusTableObjBody(codec, (*statuses).Items...)},
1206	}
1207
1208	streams, _, buf, _ := genericclioptions.NewTestIOStreams()
1209	cmd := NewCmdGet("kubectl", tf, streams)
1210	cmd.SetOutput(buf)
1211	cmd.Run(cmd, []string{"componentstatuses"})
1212
1213	expected := `NAME            STATUS      MESSAGE   ERROR
1214servergood      Healthy     ok
1215serverbad       Unhealthy             bad status: 500
1216serverunknown   Unhealthy             fizzbuzz error
1217`
1218	if e, a := expected, buf.String(); e != a {
1219		t.Errorf("expected\n%v\ngot\n%v", e, a)
1220	}
1221}
1222
1223func TestGetMixedGenericObjects(t *testing.T) {
1224	cmdtesting.InitTestErrorHandler(t)
1225
1226	// ensure that a runtime.Object without
1227	// an ObjectMeta field is handled properly
1228	structuredObj := &metav1.Status{
1229		TypeMeta: metav1.TypeMeta{
1230			Kind:       "Status",
1231			APIVersion: "v1",
1232		},
1233		Status:  "Success",
1234		Message: "",
1235		Reason:  "",
1236		Code:    0,
1237	}
1238
1239	tf := cmdtesting.NewTestFactory().WithNamespace("test")
1240	defer tf.Cleanup()
1241	codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
1242
1243	tf.UnstructuredClient = &fake.RESTClient{
1244		NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
1245		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
1246			switch req.URL.Path {
1247			case "/namespaces/test/pods":
1248				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, structuredObj)}, nil
1249			default:
1250				t.Fatalf("request url: %#v,and request: %#v", req.URL, req)
1251				return nil, nil
1252			}
1253		}),
1254	}
1255	tf.ClientConfigVal = cmdtesting.DefaultClientConfig()
1256
1257	streams, _, buf, _ := genericclioptions.NewTestIOStreams()
1258	cmd := NewCmdGet("kubectl", tf, streams)
1259	cmd.SetOutput(buf)
1260	cmd.Flags().Set("output", "json")
1261	cmd.Run(cmd, []string{"pods"})
1262
1263	expected := `{
1264    "apiVersion": "v1",
1265    "items": [
1266        {
1267            "apiVersion": "v1",
1268            "kind": "Status",
1269            "metadata": {},
1270            "status": "Success"
1271        }
1272    ],
1273    "kind": "List",
1274    "metadata": {
1275        "resourceVersion": "",
1276        "selfLink": ""
1277    }
1278}
1279`
1280	if e, a := expected, buf.String(); e != a {
1281		t.Errorf("expected\n%v\ngot\n%v", e, a)
1282	}
1283}
1284
1285func TestGetMultipleTypeObjects(t *testing.T) {
1286	pods, svc, _ := cmdtesting.TestData()
1287
1288	tf := cmdtesting.NewTestFactory().WithNamespace("test")
1289	defer tf.Cleanup()
1290	codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
1291
1292	tf.UnstructuredClient = &fake.RESTClient{
1293		NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
1294		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
1295			switch req.URL.Path {
1296			case "/namespaces/test/pods":
1297				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, pods)}, nil
1298			case "/namespaces/test/services":
1299				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, svc)}, nil
1300			default:
1301				t.Fatalf("request url: %#v,and request: %#v", req.URL, req)
1302				return nil, nil
1303			}
1304		}),
1305	}
1306
1307	streams, _, buf, _ := genericclioptions.NewTestIOStreams()
1308	cmd := NewCmdGet("kubectl", tf, streams)
1309	cmd.SetOutput(buf)
1310	cmd.Run(cmd, []string{"pods,services"})
1311
1312	expected := `NAME      AGE
1313pod/foo   <unknown>
1314pod/bar   <unknown>
1315
1316NAME          AGE
1317service/baz   <unknown>
1318`
1319	if e, a := expected, buf.String(); e != a {
1320		t.Errorf("expected\n%v\ngot\n%v", e, a)
1321	}
1322}
1323
1324func TestGetMultipleTypeTableObjects(t *testing.T) {
1325	pods, svc, _ := cmdtesting.TestData()
1326
1327	tf := cmdtesting.NewTestFactory().WithNamespace("test")
1328	defer tf.Cleanup()
1329	codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
1330
1331	tf.UnstructuredClient = &fake.RESTClient{
1332		NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
1333		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
1334			switch req.URL.Path {
1335			case "/namespaces/test/pods":
1336				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: podTableObjBody(codec, pods.Items...)}, nil
1337			case "/namespaces/test/services":
1338				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: serviceTableObjBody(codec, svc.Items...)}, nil
1339			default:
1340				t.Fatalf("request url: %#v,and request: %#v", req.URL, req)
1341				return nil, nil
1342			}
1343		}),
1344	}
1345
1346	streams, _, buf, _ := genericclioptions.NewTestIOStreams()
1347	cmd := NewCmdGet("kubectl", tf, streams)
1348	cmd.SetOutput(buf)
1349	cmd.Run(cmd, []string{"pods,services"})
1350
1351	expected := `NAME      READY   STATUS   RESTARTS   AGE
1352pod/foo   0/0              0          <unknown>
1353pod/bar   0/0              0          <unknown>
1354
1355NAME          TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
1356service/baz   ClusterIP   <none>       <none>        <none>    <unknown>
1357`
1358	if e, a := expected, buf.String(); e != a {
1359		t.Errorf("expected\n%v\ngot\n%v", e, a)
1360	}
1361}
1362
1363func TestGetMultipleTypeObjectsAsList(t *testing.T) {
1364	pods, svc, _ := cmdtesting.TestData()
1365
1366	tf := cmdtesting.NewTestFactory().WithNamespace("test")
1367	defer tf.Cleanup()
1368	codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
1369
1370	tf.UnstructuredClient = &fake.RESTClient{
1371		NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
1372		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
1373			switch req.URL.Path {
1374			case "/namespaces/test/pods":
1375				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, pods)}, nil
1376			case "/namespaces/test/services":
1377				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, svc)}, nil
1378			default:
1379				t.Fatalf("request url: %#v,and request: %#v", req.URL, req)
1380				return nil, nil
1381			}
1382		}),
1383	}
1384	tf.ClientConfigVal = cmdtesting.DefaultClientConfig()
1385
1386	streams, _, buf, _ := genericclioptions.NewTestIOStreams()
1387	cmd := NewCmdGet("kubectl", tf, streams)
1388	cmd.SetOutput(buf)
1389
1390	cmd.Flags().Set("output", "json")
1391	cmd.Run(cmd, []string{"pods,services"})
1392
1393	expected := `{
1394    "apiVersion": "v1",
1395    "items": [
1396        {
1397            "apiVersion": "v1",
1398            "kind": "Pod",
1399            "metadata": {
1400                "creationTimestamp": null,
1401                "name": "foo",
1402                "namespace": "test",
1403                "resourceVersion": "10"
1404            },
1405            "spec": {
1406                "containers": null,
1407                "dnsPolicy": "ClusterFirst",
1408                "enableServiceLinks": true,
1409                "restartPolicy": "Always",
1410                "securityContext": {},
1411                "terminationGracePeriodSeconds": 30
1412            },
1413            "status": {}
1414        },
1415        {
1416            "apiVersion": "v1",
1417            "kind": "Pod",
1418            "metadata": {
1419                "creationTimestamp": null,
1420                "name": "bar",
1421                "namespace": "test",
1422                "resourceVersion": "11"
1423            },
1424            "spec": {
1425                "containers": null,
1426                "dnsPolicy": "ClusterFirst",
1427                "enableServiceLinks": true,
1428                "restartPolicy": "Always",
1429                "securityContext": {},
1430                "terminationGracePeriodSeconds": 30
1431            },
1432            "status": {}
1433        },
1434        {
1435            "apiVersion": "v1",
1436            "kind": "Service",
1437            "metadata": {
1438                "creationTimestamp": null,
1439                "name": "baz",
1440                "namespace": "test",
1441                "resourceVersion": "12"
1442            },
1443            "spec": {
1444                "sessionAffinity": "None",
1445                "type": "ClusterIP"
1446            },
1447            "status": {
1448                "loadBalancer": {}
1449            }
1450        }
1451    ],
1452    "kind": "List",
1453    "metadata": {
1454        "resourceVersion": "",
1455        "selfLink": ""
1456    }
1457}
1458`
1459	if e, a := expected, buf.String(); e != a {
1460		t.Errorf("did not match: %v", diff.StringDiff(e, a))
1461	}
1462}
1463
1464func TestGetMultipleTypeObjectsWithLabelSelector(t *testing.T) {
1465	pods, svc, _ := cmdtesting.TestData()
1466
1467	tf := cmdtesting.NewTestFactory().WithNamespace("test")
1468	defer tf.Cleanup()
1469	codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
1470
1471	tf.UnstructuredClient = &fake.RESTClient{
1472		NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
1473		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
1474			if req.URL.Query().Get(metav1.LabelSelectorQueryParam("v1")) != "a=b" {
1475				t.Fatalf("request url: %#v,and request: %#v", req.URL, req)
1476			}
1477			switch req.URL.Path {
1478			case "/namespaces/test/pods":
1479				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, pods)}, nil
1480			case "/namespaces/test/services":
1481				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, svc)}, nil
1482			default:
1483				t.Fatalf("request url: %#v,and request: %#v", req.URL, req)
1484				return nil, nil
1485			}
1486		}),
1487	}
1488
1489	streams, _, buf, _ := genericclioptions.NewTestIOStreams()
1490	cmd := NewCmdGet("kubectl", tf, streams)
1491	cmd.SetOutput(buf)
1492
1493	cmd.Flags().Set("selector", "a=b")
1494	cmd.Run(cmd, []string{"pods,services"})
1495
1496	expected := `NAME      AGE
1497pod/foo   <unknown>
1498pod/bar   <unknown>
1499
1500NAME          AGE
1501service/baz   <unknown>
1502`
1503	if e, a := expected, buf.String(); e != a {
1504		t.Errorf("expected\n%v\ngot\n%v", e, a)
1505	}
1506}
1507
1508func TestGetMultipleTypeTableObjectsWithLabelSelector(t *testing.T) {
1509	pods, svc, _ := cmdtesting.TestData()
1510
1511	tf := cmdtesting.NewTestFactory().WithNamespace("test")
1512	defer tf.Cleanup()
1513	codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
1514
1515	tf.UnstructuredClient = &fake.RESTClient{
1516		NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
1517		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
1518			if req.URL.Query().Get(metav1.LabelSelectorQueryParam("v1")) != "a=b" {
1519				t.Fatalf("request url: %#v,and request: %#v", req.URL, req)
1520			}
1521			switch req.URL.Path {
1522			case "/namespaces/test/pods":
1523				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: podTableObjBody(codec, pods.Items...)}, nil
1524			case "/namespaces/test/services":
1525				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: serviceTableObjBody(codec, svc.Items...)}, nil
1526			default:
1527				t.Fatalf("request url: %#v,and request: %#v", req.URL, req)
1528				return nil, nil
1529			}
1530		}),
1531	}
1532
1533	streams, _, buf, _ := genericclioptions.NewTestIOStreams()
1534	cmd := NewCmdGet("kubectl", tf, streams)
1535	cmd.SetOutput(buf)
1536
1537	cmd.Flags().Set("selector", "a=b")
1538	cmd.Run(cmd, []string{"pods,services"})
1539
1540	expected := `NAME      READY   STATUS   RESTARTS   AGE
1541pod/foo   0/0              0          <unknown>
1542pod/bar   0/0              0          <unknown>
1543
1544NAME          TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
1545service/baz   ClusterIP   <none>       <none>        <none>    <unknown>
1546`
1547	if e, a := expected, buf.String(); e != a {
1548		t.Errorf("expected\n%v\ngot\n%v", e, a)
1549	}
1550}
1551
1552func TestGetMultipleTypeObjectsWithFieldSelector(t *testing.T) {
1553	pods, svc, _ := cmdtesting.TestData()
1554
1555	tf := cmdtesting.NewTestFactory().WithNamespace("test")
1556	defer tf.Cleanup()
1557	codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
1558
1559	tf.UnstructuredClient = &fake.RESTClient{
1560		NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
1561		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
1562			if req.URL.Query().Get(metav1.FieldSelectorQueryParam("v1")) != "a=b" {
1563				t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
1564			}
1565			switch req.URL.Path {
1566			case "/namespaces/test/pods":
1567				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, pods)}, nil
1568			case "/namespaces/test/services":
1569				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, svc)}, nil
1570			default:
1571				t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
1572				return nil, nil
1573			}
1574		}),
1575	}
1576
1577	streams, _, buf, _ := genericclioptions.NewTestIOStreams()
1578	cmd := NewCmdGet("kubectl", tf, streams)
1579	cmd.SetOutput(buf)
1580
1581	cmd.Flags().Set("field-selector", "a=b")
1582	cmd.Run(cmd, []string{"pods,services"})
1583
1584	expected := `NAME      AGE
1585pod/foo   <unknown>
1586pod/bar   <unknown>
1587
1588NAME          AGE
1589service/baz   <unknown>
1590`
1591	if e, a := expected, buf.String(); e != a {
1592		t.Errorf("expected\n%v\ngot\n%v", e, a)
1593	}
1594}
1595
1596func TestGetMultipleTypeTableObjectsWithFieldSelector(t *testing.T) {
1597	pods, svc, _ := cmdtesting.TestData()
1598
1599	tf := cmdtesting.NewTestFactory().WithNamespace("test")
1600	defer tf.Cleanup()
1601	codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
1602
1603	tf.UnstructuredClient = &fake.RESTClient{
1604		NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
1605		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
1606			if req.URL.Query().Get(metav1.FieldSelectorQueryParam("v1")) != "a=b" {
1607				t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
1608			}
1609			switch req.URL.Path {
1610			case "/namespaces/test/pods":
1611				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: podTableObjBody(codec, pods.Items...)}, nil
1612			case "/namespaces/test/services":
1613				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: serviceTableObjBody(codec, svc.Items...)}, nil
1614			default:
1615				t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
1616				return nil, nil
1617			}
1618		}),
1619	}
1620
1621	streams, _, buf, _ := genericclioptions.NewTestIOStreams()
1622	cmd := NewCmdGet("kubectl", tf, streams)
1623	cmd.SetOutput(buf)
1624
1625	cmd.Flags().Set("field-selector", "a=b")
1626	cmd.Run(cmd, []string{"pods,services"})
1627
1628	expected := `NAME      READY   STATUS   RESTARTS   AGE
1629pod/foo   0/0              0          <unknown>
1630pod/bar   0/0              0          <unknown>
1631
1632NAME          TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
1633service/baz   ClusterIP   <none>       <none>        <none>    <unknown>
1634`
1635	if e, a := expected, buf.String(); e != a {
1636		t.Errorf("expected\n%v\ngot\n%v", e, a)
1637	}
1638}
1639
1640func TestGetMultipleTypeObjectsWithDirectReference(t *testing.T) {
1641	_, svc, _ := cmdtesting.TestData()
1642	node := &corev1.Node{
1643		ObjectMeta: metav1.ObjectMeta{
1644			Name: "foo",
1645		},
1646	}
1647
1648	tf := cmdtesting.NewTestFactory().WithNamespace("test")
1649	defer tf.Cleanup()
1650	codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
1651
1652	tf.UnstructuredClient = &fake.RESTClient{
1653		NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
1654		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
1655			switch req.URL.Path {
1656			case "/nodes/foo":
1657				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, node)}, nil
1658			case "/namespaces/test/services/bar":
1659				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &svc.Items[0])}, nil
1660			default:
1661				t.Fatalf("request url: %#v,and request: %#v", req.URL, req)
1662				return nil, nil
1663			}
1664		}),
1665	}
1666
1667	streams, _, buf, _ := genericclioptions.NewTestIOStreams()
1668	cmd := NewCmdGet("kubectl", tf, streams)
1669	cmd.SetOutput(buf)
1670
1671	cmd.Run(cmd, []string{"services/bar", "node/foo"})
1672
1673	expected := `NAME          AGE
1674service/baz   <unknown>
1675
1676NAME       AGE
1677node/foo   <unknown>
1678`
1679	if e, a := expected, buf.String(); e != a {
1680		t.Errorf("expected\n%v\ngot\n%v", e, a)
1681	}
1682}
1683
1684func TestGetMultipleTypeTableObjectsWithDirectReference(t *testing.T) {
1685	_, svc, _ := cmdtesting.TestData()
1686	node := &corev1.Node{
1687		ObjectMeta: metav1.ObjectMeta{
1688			Name: "foo",
1689		},
1690	}
1691
1692	tf := cmdtesting.NewTestFactory().WithNamespace("test")
1693	defer tf.Cleanup()
1694	codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
1695
1696	tf.UnstructuredClient = &fake.RESTClient{
1697		NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
1698		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
1699			switch req.URL.Path {
1700			case "/nodes/foo":
1701				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: nodeTableObjBody(codec, *node)}, nil
1702			case "/namespaces/test/services/bar":
1703				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: serviceTableObjBody(codec, svc.Items[0])}, nil
1704			default:
1705				t.Fatalf("request url: %#v,and request: %#v", req.URL, req)
1706				return nil, nil
1707			}
1708		}),
1709	}
1710
1711	streams, _, buf, _ := genericclioptions.NewTestIOStreams()
1712	cmd := NewCmdGet("kubectl", tf, streams)
1713	cmd.SetOutput(buf)
1714
1715	cmd.Run(cmd, []string{"services/bar", "node/foo"})
1716
1717	expected := `NAME          TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
1718service/baz   ClusterIP   <none>       <none>        <none>    <unknown>
1719
1720NAME       STATUS    ROLES    AGE         VERSION
1721node/foo   Unknown   <none>   <unknown>
1722`
1723	if e, a := expected, buf.String(); e != a {
1724		t.Errorf("expected\n%v\ngot\n%v", e, a)
1725	}
1726}
1727
1728func watchTestData() ([]corev1.Pod, []watch.Event) {
1729	pods := []corev1.Pod{
1730		{
1731			ObjectMeta: metav1.ObjectMeta{
1732				Name:            "bar",
1733				Namespace:       "test",
1734				ResourceVersion: "9",
1735			},
1736			Spec: corev1.PodSpec{
1737				RestartPolicy:                 corev1.RestartPolicyAlways,
1738				DNSPolicy:                     corev1.DNSClusterFirst,
1739				TerminationGracePeriodSeconds: &grace,
1740				SecurityContext:               &corev1.PodSecurityContext{},
1741				EnableServiceLinks:            &enableServiceLinks,
1742			},
1743		},
1744		{
1745			ObjectMeta: metav1.ObjectMeta{
1746				Name:            "foo",
1747				Namespace:       "test",
1748				ResourceVersion: "10",
1749			},
1750			Spec: corev1.PodSpec{
1751				RestartPolicy:                 corev1.RestartPolicyAlways,
1752				DNSPolicy:                     corev1.DNSClusterFirst,
1753				TerminationGracePeriodSeconds: &grace,
1754				SecurityContext:               &corev1.PodSecurityContext{},
1755				EnableServiceLinks:            &enableServiceLinks,
1756			},
1757		},
1758	}
1759	events := []watch.Event{
1760		// current state events
1761		{
1762			Type: watch.Added,
1763			Object: &corev1.Pod{
1764				ObjectMeta: metav1.ObjectMeta{
1765					Name:            "bar",
1766					Namespace:       "test",
1767					ResourceVersion: "9",
1768				},
1769				Spec: corev1.PodSpec{
1770					RestartPolicy:                 corev1.RestartPolicyAlways,
1771					DNSPolicy:                     corev1.DNSClusterFirst,
1772					TerminationGracePeriodSeconds: &grace,
1773					SecurityContext:               &corev1.PodSecurityContext{},
1774					EnableServiceLinks:            &enableServiceLinks,
1775				},
1776			},
1777		},
1778		{
1779			Type: watch.Added,
1780			Object: &corev1.Pod{
1781				ObjectMeta: metav1.ObjectMeta{
1782					Name:            "foo",
1783					Namespace:       "test",
1784					ResourceVersion: "10",
1785				},
1786				Spec: corev1.PodSpec{
1787					RestartPolicy:                 corev1.RestartPolicyAlways,
1788					DNSPolicy:                     corev1.DNSClusterFirst,
1789					TerminationGracePeriodSeconds: &grace,
1790					SecurityContext:               &corev1.PodSecurityContext{},
1791					EnableServiceLinks:            &enableServiceLinks,
1792				},
1793			},
1794		},
1795		// resource events
1796		{
1797			Type: watch.Modified,
1798			Object: &corev1.Pod{
1799				ObjectMeta: metav1.ObjectMeta{
1800					Name:            "foo",
1801					Namespace:       "test",
1802					ResourceVersion: "11",
1803				},
1804				Spec: corev1.PodSpec{
1805					RestartPolicy:                 corev1.RestartPolicyAlways,
1806					DNSPolicy:                     corev1.DNSClusterFirst,
1807					TerminationGracePeriodSeconds: &grace,
1808					SecurityContext:               &corev1.PodSecurityContext{},
1809					EnableServiceLinks:            &enableServiceLinks,
1810				},
1811			},
1812		},
1813		{
1814			Type: watch.Deleted,
1815			Object: &corev1.Pod{
1816				ObjectMeta: metav1.ObjectMeta{
1817					Name:            "foo",
1818					Namespace:       "test",
1819					ResourceVersion: "12",
1820				},
1821				Spec: corev1.PodSpec{
1822					RestartPolicy:                 corev1.RestartPolicyAlways,
1823					DNSPolicy:                     corev1.DNSClusterFirst,
1824					TerminationGracePeriodSeconds: &grace,
1825					SecurityContext:               &corev1.PodSecurityContext{},
1826					EnableServiceLinks:            &enableServiceLinks,
1827				},
1828			},
1829		},
1830	}
1831	return pods, events
1832}
1833
1834func TestWatchLabelSelector(t *testing.T) {
1835	pods, events := watchTestData()
1836
1837	tf := cmdtesting.NewTestFactory().WithNamespace("test")
1838	defer tf.Cleanup()
1839	codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
1840
1841	podList := &corev1.PodList{
1842		Items: pods,
1843		ListMeta: metav1.ListMeta{
1844			ResourceVersion: "10",
1845		},
1846	}
1847	tf.UnstructuredClient = &fake.RESTClient{
1848		NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
1849		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
1850			if req.URL.Query().Get(metav1.LabelSelectorQueryParam("v1")) != "a=b" {
1851				t.Fatalf("request url: %#v,and request: %#v", req.URL, req)
1852			}
1853			switch req.URL.Path {
1854			case "/namespaces/test/pods":
1855				if req.URL.Query().Get("watch") == "true" {
1856					return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: watchBody(codec, events[2:])}, nil
1857				}
1858				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, podList)}, nil
1859			default:
1860				t.Fatalf("request url: %#v,and request: %#v", req.URL, req)
1861				return nil, nil
1862			}
1863		}),
1864	}
1865
1866	streams, _, buf, _ := genericclioptions.NewTestIOStreams()
1867	cmd := NewCmdGet("kubectl", tf, streams)
1868	cmd.SetOutput(buf)
1869
1870	cmd.Flags().Set("watch", "true")
1871	cmd.Flags().Set("selector", "a=b")
1872	cmd.Run(cmd, []string{"pods"})
1873
1874	expected := `NAME   AGE
1875bar    <unknown>
1876foo    <unknown>
1877foo    <unknown>
1878foo    <unknown>
1879`
1880	if e, a := expected, buf.String(); e != a {
1881		t.Errorf("expected\n%v\ngot\n%v", e, a)
1882	}
1883}
1884
1885func TestWatchTableLabelSelector(t *testing.T) {
1886	pods, events := watchTestData()
1887
1888	tf := cmdtesting.NewTestFactory().WithNamespace("test")
1889	defer tf.Cleanup()
1890	codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
1891
1892	podList := &corev1.PodList{
1893		Items: pods,
1894		ListMeta: metav1.ListMeta{
1895			ResourceVersion: "10",
1896		},
1897	}
1898	tf.UnstructuredClient = &fake.RESTClient{
1899		NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
1900		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
1901			if req.URL.Query().Get(metav1.LabelSelectorQueryParam("v1")) != "a=b" {
1902				t.Fatalf("request url: %#v,and request: %#v", req.URL, req)
1903			}
1904			switch req.URL.Path {
1905			case "/namespaces/test/pods":
1906				if req.URL.Query().Get("watch") == "true" {
1907					return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: podTableWatchBody(codec, events[2:])}, nil
1908				}
1909				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: podTableObjBody(codec, podList.Items...)}, nil
1910			default:
1911				t.Fatalf("request url: %#v,and request: %#v", req.URL, req)
1912				return nil, nil
1913			}
1914		}),
1915	}
1916
1917	streams, _, buf, _ := genericclioptions.NewTestIOStreams()
1918	cmd := NewCmdGet("kubectl", tf, streams)
1919	cmd.SetOutput(buf)
1920
1921	cmd.Flags().Set("watch", "true")
1922	cmd.Flags().Set("selector", "a=b")
1923	cmd.Run(cmd, []string{"pods"})
1924
1925	expected := `NAME   READY   STATUS   RESTARTS   AGE
1926bar    0/0              0          <unknown>
1927foo    0/0              0          <unknown>
1928foo    0/0              0          <unknown>
1929foo    0/0              0          <unknown>
1930`
1931	if e, a := expected, buf.String(); e != a {
1932		t.Errorf("expected\n%v\ngot\n%v", e, a)
1933	}
1934}
1935
1936func TestWatchFieldSelector(t *testing.T) {
1937	pods, events := watchTestData()
1938
1939	tf := cmdtesting.NewTestFactory().WithNamespace("test")
1940	defer tf.Cleanup()
1941	codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
1942
1943	podList := &corev1.PodList{
1944		Items: pods,
1945		ListMeta: metav1.ListMeta{
1946			ResourceVersion: "10",
1947		},
1948	}
1949	tf.UnstructuredClient = &fake.RESTClient{
1950		NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
1951		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
1952			if req.URL.Query().Get(metav1.FieldSelectorQueryParam("v1")) != "a=b" {
1953				t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
1954			}
1955			switch req.URL.Path {
1956			case "/namespaces/test/pods":
1957				if req.URL.Query().Get("watch") == "true" {
1958					return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: watchBody(codec, events[2:])}, nil
1959				}
1960				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, podList)}, nil
1961			default:
1962				t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
1963				return nil, nil
1964			}
1965		}),
1966	}
1967
1968	streams, _, buf, _ := genericclioptions.NewTestIOStreams()
1969	cmd := NewCmdGet("kubectl", tf, streams)
1970	cmd.SetOutput(buf)
1971
1972	cmd.Flags().Set("watch", "true")
1973	cmd.Flags().Set("field-selector", "a=b")
1974	cmd.Run(cmd, []string{"pods"})
1975
1976	expected := `NAME   AGE
1977bar    <unknown>
1978foo    <unknown>
1979foo    <unknown>
1980foo    <unknown>
1981`
1982	if e, a := expected, buf.String(); e != a {
1983		t.Errorf("expected\n%v\ngot\n%v", e, a)
1984	}
1985}
1986
1987func TestWatchTableFieldSelector(t *testing.T) {
1988	pods, events := watchTestData()
1989
1990	tf := cmdtesting.NewTestFactory().WithNamespace("test")
1991	defer tf.Cleanup()
1992	codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
1993
1994	podList := &corev1.PodList{
1995		Items: pods,
1996		ListMeta: metav1.ListMeta{
1997			ResourceVersion: "10",
1998		},
1999	}
2000	tf.UnstructuredClient = &fake.RESTClient{
2001		NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
2002		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
2003			if req.URL.Query().Get(metav1.FieldSelectorQueryParam("v1")) != "a=b" {
2004				t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
2005			}
2006			switch req.URL.Path {
2007			case "/namespaces/test/pods":
2008				if req.URL.Query().Get("watch") == "true" {
2009					return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: podTableWatchBody(codec, events[2:])}, nil
2010				}
2011				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: podTableObjBody(codec, podList.Items...)}, nil
2012			default:
2013				t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
2014				return nil, nil
2015			}
2016		}),
2017	}
2018
2019	streams, _, buf, _ := genericclioptions.NewTestIOStreams()
2020	cmd := NewCmdGet("kubectl", tf, streams)
2021	cmd.SetOutput(buf)
2022
2023	cmd.Flags().Set("watch", "true")
2024	cmd.Flags().Set("field-selector", "a=b")
2025	cmd.Run(cmd, []string{"pods"})
2026
2027	expected := `NAME   READY   STATUS   RESTARTS   AGE
2028bar    0/0              0          <unknown>
2029foo    0/0              0          <unknown>
2030foo    0/0              0          <unknown>
2031foo    0/0              0          <unknown>
2032`
2033	if e, a := expected, buf.String(); e != a {
2034		t.Errorf("expected\n%v\ngot\n%v", e, a)
2035	}
2036}
2037
2038func TestWatchResource(t *testing.T) {
2039	pods, events := watchTestData()
2040
2041	tf := cmdtesting.NewTestFactory().WithNamespace("test")
2042	defer tf.Cleanup()
2043	codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
2044
2045	tf.UnstructuredClient = &fake.RESTClient{
2046		NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
2047		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
2048			switch req.URL.Path {
2049			case "/namespaces/test/pods/foo":
2050				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &pods[1])}, nil
2051			case "/namespaces/test/pods":
2052				if req.URL.Query().Get("watch") == "true" && req.URL.Query().Get("fieldSelector") == "metadata.name=foo" {
2053					return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: watchBody(codec, events[1:])}, nil
2054				}
2055				t.Fatalf("request url: %#v,and request: %#v", req.URL, req)
2056				return nil, nil
2057			default:
2058				t.Fatalf("request url: %#v,and request: %#v", req.URL, req)
2059				return nil, nil
2060			}
2061		}),
2062	}
2063
2064	streams, _, buf, _ := genericclioptions.NewTestIOStreams()
2065	cmd := NewCmdGet("kubectl", tf, streams)
2066	cmd.SetOutput(buf)
2067
2068	cmd.Flags().Set("watch", "true")
2069	cmd.Run(cmd, []string{"pods", "foo"})
2070
2071	expected := `NAME   AGE
2072foo    <unknown>
2073foo    <unknown>
2074foo    <unknown>
2075`
2076	if e, a := expected, buf.String(); e != a {
2077		t.Errorf("expected\n%v\ngot\n%v", e, a)
2078	}
2079}
2080
2081func TestWatchStatus(t *testing.T) {
2082	pods, events := watchTestData()
2083	events = append(events, watch.Event{Type: "ERROR", Object: &metav1.Status{Status: "Failure", Reason: "InternalServerError", Message: "Something happened"}})
2084
2085	tf := cmdtesting.NewTestFactory().WithNamespace("test")
2086	defer tf.Cleanup()
2087	codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
2088
2089	tf.UnstructuredClient = &fake.RESTClient{
2090		NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
2091		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
2092			switch req.URL.Path {
2093			case "/namespaces/test/pods/foo":
2094				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &pods[1])}, nil
2095			case "/namespaces/test/pods":
2096				if req.URL.Query().Get("watch") == "true" && req.URL.Query().Get("fieldSelector") == "metadata.name=foo" {
2097					return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: watchBody(codec, events[1:])}, nil
2098				}
2099				t.Fatalf("request url: %#v,and request: %#v", req.URL, req)
2100				return nil, nil
2101			default:
2102				t.Fatalf("request url: %#v,and request: %#v", req.URL, req)
2103				return nil, nil
2104			}
2105		}),
2106	}
2107
2108	streams, _, buf, _ := genericclioptions.NewTestIOStreams()
2109	cmd := NewCmdGet("kubectl", tf, streams)
2110	cmd.SetOutput(buf)
2111
2112	cmd.Flags().Set("watch", "true")
2113	cmd.Run(cmd, []string{"pods", "foo"})
2114
2115	expected := `NAME   AGE
2116foo    <unknown>
2117foo    <unknown>
2118foo    <unknown>
2119
2120STATUS    REASON                MESSAGE
2121Failure   InternalServerError   Something happened
2122`
2123	if e, a := expected, buf.String(); e != a {
2124		t.Errorf("expected\n%v\ngot\n%v", e, a)
2125	}
2126}
2127
2128func TestWatchTableResource(t *testing.T) {
2129	pods, events := watchTestData()
2130
2131	tf := cmdtesting.NewTestFactory().WithNamespace("test")
2132	defer tf.Cleanup()
2133	codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
2134
2135	tf.UnstructuredClient = &fake.RESTClient{
2136		NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
2137		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
2138			switch req.URL.Path {
2139			case "/namespaces/test/pods/foo":
2140				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: podTableObjBody(codec, pods[1])}, nil
2141			case "/namespaces/test/pods":
2142				if req.URL.Query().Get("watch") == "true" && req.URL.Query().Get("fieldSelector") == "metadata.name=foo" {
2143					return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: podTableWatchBody(codec, events[1:])}, nil
2144				}
2145				t.Fatalf("request url: %#v,and request: %#v", req.URL, req)
2146				return nil, nil
2147			default:
2148				t.Fatalf("request url: %#v,and request: %#v", req.URL, req)
2149				return nil, nil
2150			}
2151		}),
2152	}
2153
2154	streams, _, buf, _ := genericclioptions.NewTestIOStreams()
2155	cmd := NewCmdGet("kubectl", tf, streams)
2156	cmd.SetOutput(buf)
2157
2158	cmd.Flags().Set("watch", "true")
2159	cmd.Run(cmd, []string{"pods", "foo"})
2160
2161	expected := `NAME   READY   STATUS   RESTARTS   AGE
2162foo    0/0              0          <unknown>
2163foo    0/0              0          <unknown>
2164foo    0/0              0          <unknown>
2165`
2166	if e, a := expected, buf.String(); e != a {
2167		t.Errorf("expected\n%v\ngot\n%v", e, a)
2168	}
2169}
2170
2171func TestWatchResourceTable(t *testing.T) {
2172	columns := []metav1beta1.TableColumnDefinition{
2173		{Name: "Name", Type: "string", Format: "name", Description: "the name", Priority: 0},
2174		{Name: "Active", Type: "boolean", Description: "active", Priority: 0},
2175	}
2176
2177	listTable := &metav1beta1.Table{
2178		TypeMeta:          metav1.TypeMeta{APIVersion: "meta.k8s.io/v1beta1", Kind: "Table"},
2179		ColumnDefinitions: columns,
2180		Rows: []metav1beta1.TableRow{
2181			{
2182				Cells: []interface{}{"a", true},
2183				Object: runtime.RawExtension{
2184					Object: &corev1.Pod{
2185						TypeMeta:   metav1.TypeMeta{APIVersion: "v1", Kind: "Pod"},
2186						ObjectMeta: metav1.ObjectMeta{Name: "a", Namespace: "test", ResourceVersion: "10"},
2187					},
2188				},
2189			},
2190			{
2191				Cells: []interface{}{"b", true},
2192				Object: runtime.RawExtension{
2193					Object: &corev1.Pod{
2194						TypeMeta:   metav1.TypeMeta{APIVersion: "v1", Kind: "Pod"},
2195						ObjectMeta: metav1.ObjectMeta{Name: "b", Namespace: "test", ResourceVersion: "20"},
2196					},
2197				},
2198			},
2199		},
2200	}
2201
2202	events := []watch.Event{
2203		{
2204			Type: watch.Added,
2205			Object: &metav1beta1.Table{
2206				TypeMeta:          metav1.TypeMeta{APIVersion: "meta.k8s.io/v1beta1", Kind: "Table"},
2207				ColumnDefinitions: columns, // first event includes the columns
2208				Rows: []metav1beta1.TableRow{{
2209					Cells: []interface{}{"a", false},
2210					Object: runtime.RawExtension{
2211						Object: &corev1.Pod{
2212							TypeMeta:   metav1.TypeMeta{APIVersion: "v1", Kind: "Pod"},
2213							ObjectMeta: metav1.ObjectMeta{Name: "a", Namespace: "test", ResourceVersion: "30"},
2214						},
2215					},
2216				}},
2217			},
2218		},
2219		{
2220			Type: watch.Deleted,
2221			Object: &metav1beta1.Table{
2222				ColumnDefinitions: []metav1beta1.TableColumnDefinition{},
2223				Rows: []metav1beta1.TableRow{{
2224					Cells: []interface{}{"b", false},
2225					Object: runtime.RawExtension{
2226						Object: &corev1.Pod{
2227							TypeMeta:   metav1.TypeMeta{APIVersion: "v1", Kind: "Pod"},
2228							ObjectMeta: metav1.ObjectMeta{Name: "b", Namespace: "test", ResourceVersion: "40"},
2229						},
2230					},
2231				}},
2232			},
2233		},
2234	}
2235
2236	tf := cmdtesting.NewTestFactory().WithNamespace("test")
2237	defer tf.Cleanup()
2238	codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
2239
2240	tf.UnstructuredClient = &fake.RESTClient{
2241		NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
2242		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
2243			switch req.URL.Path {
2244			case "/namespaces/test/pods":
2245				if req.URL.Query().Get("watch") != "true" && req.URL.Query().Get("fieldSelector") == "" {
2246					return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, listTable)}, nil
2247				}
2248				if req.URL.Query().Get("watch") == "true" && req.URL.Query().Get("fieldSelector") == "" {
2249					return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: watchBody(codec, events)}, nil
2250				}
2251				t.Fatalf("request url: %#v,and request: %#v", req.URL, req)
2252				return nil, nil
2253			default:
2254				t.Fatalf("request url: %#v,and request: %#v", req.URL, req)
2255				return nil, nil
2256			}
2257		}),
2258	}
2259
2260	streams, _, buf, _ := genericclioptions.NewTestIOStreams()
2261	cmd := NewCmdGet("kubectl", tf, streams)
2262	cmd.SetOutput(buf)
2263
2264	cmd.Flags().Set("watch", "true")
2265	cmd.Run(cmd, []string{"pods"})
2266
2267	expected := `NAME   ACTIVE
2268a      true
2269b      true
2270a      false
2271b      false
2272`
2273	if e, a := expected, buf.String(); e != a {
2274		t.Errorf("expected\n%v\ngot\n%v", e, a)
2275	}
2276}
2277
2278func TestWatchResourceWatchEvents(t *testing.T) {
2279
2280	testcases := []struct {
2281		format   string
2282		table    bool
2283		expected string
2284	}{
2285		{
2286			format: "",
2287			expected: `EVENT      NAMESPACE   NAME      AGE
2288ADDED      test        pod/bar   <unknown>
2289ADDED      test        pod/foo   <unknown>
2290MODIFIED   test        pod/foo   <unknown>
2291DELETED    test        pod/foo   <unknown>
2292`,
2293		},
2294		{
2295			format: "",
2296			table:  true,
2297			expected: `EVENT      NAMESPACE   NAME      READY   STATUS   RESTARTS   AGE
2298ADDED      test        pod/bar   0/0              0          <unknown>
2299ADDED      test        pod/foo   0/0              0          <unknown>
2300MODIFIED   test        pod/foo   0/0              0          <unknown>
2301DELETED    test        pod/foo   0/0              0          <unknown>
2302`,
2303		},
2304		{
2305			format: "wide",
2306			table:  true,
2307			expected: `EVENT      NAMESPACE   NAME      READY   STATUS   RESTARTS   AGE         IP       NODE     NOMINATED NODE   READINESS GATES
2308ADDED      test        pod/bar   0/0              0          <unknown>   <none>   <none>   <none>           <none>
2309ADDED      test        pod/foo   0/0              0          <unknown>   <none>   <none>   <none>           <none>
2310MODIFIED   test        pod/foo   0/0              0          <unknown>   <none>   <none>   <none>           <none>
2311DELETED    test        pod/foo   0/0              0          <unknown>   <none>   <none>   <none>           <none>
2312`,
2313		},
2314		{
2315			format: "json",
2316			expected: `{"type":"ADDED","object":{"apiVersion":"v1","kind":"Pod","metadata":{"creationTimestamp":null,"name":"bar","namespace":"test","resourceVersion":"9"},"spec":{"containers":null,"dnsPolicy":"ClusterFirst","enableServiceLinks":true,"restartPolicy":"Always","securityContext":{},"terminationGracePeriodSeconds":30},"status":{}}}
2317{"type":"ADDED","object":{"apiVersion":"v1","kind":"Pod","metadata":{"creationTimestamp":null,"name":"foo","namespace":"test","resourceVersion":"10"},"spec":{"containers":null,"dnsPolicy":"ClusterFirst","enableServiceLinks":true,"restartPolicy":"Always","securityContext":{},"terminationGracePeriodSeconds":30},"status":{}}}
2318{"type":"MODIFIED","object":{"apiVersion":"v1","kind":"Pod","metadata":{"creationTimestamp":null,"name":"foo","namespace":"test","resourceVersion":"11"},"spec":{"containers":null,"dnsPolicy":"ClusterFirst","enableServiceLinks":true,"restartPolicy":"Always","securityContext":{},"terminationGracePeriodSeconds":30},"status":{}}}
2319{"type":"DELETED","object":{"apiVersion":"v1","kind":"Pod","metadata":{"creationTimestamp":null,"name":"foo","namespace":"test","resourceVersion":"12"},"spec":{"containers":null,"dnsPolicy":"ClusterFirst","enableServiceLinks":true,"restartPolicy":"Always","securityContext":{},"terminationGracePeriodSeconds":30},"status":{}}}
2320`,
2321		},
2322		{
2323			format: "yaml",
2324			expected: `object:
2325  apiVersion: v1
2326  kind: Pod
2327  metadata:
2328    creationTimestamp: null
2329    name: bar
2330    namespace: test
2331    resourceVersion: "9"
2332  spec:
2333    containers: null
2334    dnsPolicy: ClusterFirst
2335    enableServiceLinks: true
2336    restartPolicy: Always
2337    securityContext: {}
2338    terminationGracePeriodSeconds: 30
2339  status: {}
2340type: ADDED
2341---
2342object:
2343  apiVersion: v1
2344  kind: Pod
2345  metadata:
2346    creationTimestamp: null
2347    name: foo
2348    namespace: test
2349    resourceVersion: "10"
2350  spec:
2351    containers: null
2352    dnsPolicy: ClusterFirst
2353    enableServiceLinks: true
2354    restartPolicy: Always
2355    securityContext: {}
2356    terminationGracePeriodSeconds: 30
2357  status: {}
2358type: ADDED
2359---
2360object:
2361  apiVersion: v1
2362  kind: Pod
2363  metadata:
2364    creationTimestamp: null
2365    name: foo
2366    namespace: test
2367    resourceVersion: "11"
2368  spec:
2369    containers: null
2370    dnsPolicy: ClusterFirst
2371    enableServiceLinks: true
2372    restartPolicy: Always
2373    securityContext: {}
2374    terminationGracePeriodSeconds: 30
2375  status: {}
2376type: MODIFIED
2377---
2378object:
2379  apiVersion: v1
2380  kind: Pod
2381  metadata:
2382    creationTimestamp: null
2383    name: foo
2384    namespace: test
2385    resourceVersion: "12"
2386  spec:
2387    containers: null
2388    dnsPolicy: ClusterFirst
2389    enableServiceLinks: true
2390    restartPolicy: Always
2391    securityContext: {}
2392    terminationGracePeriodSeconds: 30
2393  status: {}
2394type: DELETED
2395`,
2396		},
2397		{
2398			format: `jsonpath={.type},{.object.metadata.name},{.object.metadata.resourceVersion}{"\n"}`,
2399			expected: `ADDED,bar,9
2400ADDED,foo,10
2401MODIFIED,foo,11
2402DELETED,foo,12
2403`,
2404		},
2405		{
2406			format: `go-template={{.type}},{{.object.metadata.name}},{{.object.metadata.resourceVersion}}{{"\n"}}`,
2407			expected: `ADDED,bar,9
2408ADDED,foo,10
2409MODIFIED,foo,11
2410DELETED,foo,12
2411`,
2412		},
2413		{
2414			format: `custom-columns=TYPE:.type,NAME:.object.metadata.name,RSRC:.object.metadata.resourceVersion`,
2415			expected: `TYPE    NAME   RSRC
2416ADDED   bar    9
2417ADDED   foo    10
2418MODIFIED   foo    11
2419DELETED    foo    12
2420`,
2421		},
2422		{
2423			format: `name`,
2424			expected: `pod/bar
2425pod/foo
2426pod/foo
2427pod/foo
2428`,
2429		},
2430	}
2431
2432	for _, tc := range testcases {
2433		t.Run(fmt.Sprintf("%s, table=%v", tc.format, tc.table), func(t *testing.T) {
2434			pods, events := watchTestData()
2435
2436			tf := cmdtesting.NewTestFactory().WithNamespace("test")
2437			defer tf.Cleanup()
2438			codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
2439
2440			podList := &corev1.PodList{
2441				Items: pods,
2442				ListMeta: metav1.ListMeta{
2443					ResourceVersion: "10",
2444				},
2445			}
2446
2447			tf.UnstructuredClient = &fake.RESTClient{
2448				NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
2449				Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
2450					switch req.URL.Path {
2451					case "/pods":
2452						if req.URL.Query().Get("watch") == "true" {
2453							if tc.table {
2454								return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: podTableWatchBody(codec, events[2:])}, nil
2455							} else {
2456								return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: watchBody(codec, events[2:])}, nil
2457							}
2458						}
2459
2460						if tc.table {
2461							return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: podTableObjBody(codec, podList.Items...)}, nil
2462						} else {
2463							return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, podList)}, nil
2464						}
2465					default:
2466						t.Fatalf("request url: %#v,and request: %#v", req.URL, req)
2467						return nil, nil
2468					}
2469				}),
2470			}
2471
2472			streams, _, buf, _ := genericclioptions.NewTestIOStreams()
2473			cmd := NewCmdGet("kubectl", tf, streams)
2474			cmd.SetOutput(buf)
2475
2476			cmd.Flags().Set("watch", "true")
2477			cmd.Flags().Set("all-namespaces", "true")
2478			cmd.Flags().Set("show-kind", "true")
2479			cmd.Flags().Set("output-watch-events", "true")
2480			if len(tc.format) > 0 {
2481				cmd.Flags().Set("output", tc.format)
2482			}
2483
2484			cmd.Run(cmd, []string{"pods"})
2485			if e, a := tc.expected, buf.String(); e != a {
2486				t.Errorf("expected\n%v\ngot\n%v", e, a)
2487			}
2488		})
2489	}
2490}
2491
2492func TestWatchResourceIdentifiedByFile(t *testing.T) {
2493	pods, events := watchTestData()
2494
2495	tf := cmdtesting.NewTestFactory().WithNamespace("test")
2496	defer tf.Cleanup()
2497	codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
2498
2499	tf.UnstructuredClient = &fake.RESTClient{
2500		NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
2501		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
2502			switch req.URL.Path {
2503			case "/namespaces/test/replicationcontrollers/cassandra":
2504				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &pods[1])}, nil
2505			case "/namespaces/test/replicationcontrollers":
2506				if req.URL.Query().Get("watch") == "true" && req.URL.Query().Get("fieldSelector") == "metadata.name=cassandra" {
2507					return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: watchBody(codec, events[1:])}, nil
2508				}
2509				t.Fatalf("request url: %#v,and request: %#v", req.URL, req)
2510				return nil, nil
2511			default:
2512				t.Fatalf("request url: %#v,and request: %#v", req.URL, req)
2513				return nil, nil
2514			}
2515		}),
2516	}
2517
2518	streams, _, buf, _ := genericclioptions.NewTestIOStreams()
2519	cmd := NewCmdGet("kubectl", tf, streams)
2520	cmd.SetOutput(buf)
2521
2522	cmd.Flags().Set("watch", "true")
2523	cmd.Flags().Set("filename", "../../../testdata/controller.yaml")
2524	cmd.Run(cmd, []string{})
2525
2526	expected := `NAME   AGE
2527foo    <unknown>
2528foo    <unknown>
2529foo    <unknown>
2530`
2531	if e, a := expected, buf.String(); e != a {
2532		t.Errorf("expected\n%v\ngot\n%v", e, a)
2533	}
2534}
2535
2536func TestWatchOnlyResource(t *testing.T) {
2537	pods, events := watchTestData()
2538
2539	tf := cmdtesting.NewTestFactory().WithNamespace("test")
2540	defer tf.Cleanup()
2541	codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
2542
2543	tf.UnstructuredClient = &fake.RESTClient{
2544		NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
2545		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
2546			switch req.URL.Path {
2547			case "/namespaces/test/pods/foo":
2548				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &pods[1])}, nil
2549			case "/namespaces/test/pods":
2550				if req.URL.Query().Get("watch") == "true" && req.URL.Query().Get("fieldSelector") == "metadata.name=foo" {
2551					return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: watchBody(codec, events[1:])}, nil
2552				}
2553				t.Fatalf("request url: %#v,and request: %#v", req.URL, req)
2554				return nil, nil
2555			default:
2556				t.Fatalf("request url: %#v,and request: %#v", req.URL, req)
2557				return nil, nil
2558			}
2559		}),
2560	}
2561
2562	streams, _, buf, _ := genericclioptions.NewTestIOStreams()
2563	cmd := NewCmdGet("kubectl", tf, streams)
2564	cmd.SetOutput(buf)
2565
2566	cmd.Flags().Set("watch-only", "true")
2567	cmd.Run(cmd, []string{"pods", "foo"})
2568
2569	expected := `NAME   AGE
2570foo    <unknown>
2571foo    <unknown>
2572`
2573	if e, a := expected, buf.String(); e != a {
2574		t.Errorf("expected\n%v\ngot\n%v", e, a)
2575	}
2576}
2577
2578func TestWatchOnlyTableResource(t *testing.T) {
2579	pods, events := watchTestData()
2580
2581	tf := cmdtesting.NewTestFactory().WithNamespace("test")
2582	defer tf.Cleanup()
2583	codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
2584
2585	tf.UnstructuredClient = &fake.RESTClient{
2586		NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
2587		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
2588			switch req.URL.Path {
2589			case "/namespaces/test/pods/foo":
2590				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: podTableObjBody(codec, pods[1])}, nil
2591			case "/namespaces/test/pods":
2592				if req.URL.Query().Get("watch") == "true" && req.URL.Query().Get("fieldSelector") == "metadata.name=foo" {
2593					return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: podTableWatchBody(codec, events[1:])}, nil
2594				}
2595				t.Fatalf("request url: %#v,and request: %#v", req.URL, req)
2596				return nil, nil
2597			default:
2598				t.Fatalf("request url: %#v,and request: %#v", req.URL, req)
2599				return nil, nil
2600			}
2601		}),
2602	}
2603
2604	streams, _, buf, _ := genericclioptions.NewTestIOStreams()
2605	cmd := NewCmdGet("kubectl", tf, streams)
2606	cmd.SetOutput(buf)
2607
2608	cmd.Flags().Set("watch-only", "true")
2609	cmd.Run(cmd, []string{"pods", "foo"})
2610
2611	expected := `NAME   READY   STATUS   RESTARTS   AGE
2612foo    0/0              0          <unknown>
2613foo    0/0              0          <unknown>
2614`
2615	if e, a := expected, buf.String(); e != a {
2616		t.Errorf("expected\n%v\ngot\n%v", e, a)
2617	}
2618}
2619
2620func TestWatchOnlyList(t *testing.T) {
2621	pods, events := watchTestData()
2622
2623	tf := cmdtesting.NewTestFactory().WithNamespace("test")
2624	defer tf.Cleanup()
2625	codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
2626
2627	podList := &corev1.PodList{
2628		Items: pods,
2629		ListMeta: metav1.ListMeta{
2630			ResourceVersion: "10",
2631		},
2632	}
2633	tf.UnstructuredClient = &fake.RESTClient{
2634		NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
2635		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
2636			switch req.URL.Path {
2637			case "/namespaces/test/pods":
2638				if req.URL.Query().Get("watch") == "true" {
2639					return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: watchBody(codec, events[2:])}, nil
2640				}
2641				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, podList)}, nil
2642			default:
2643				t.Fatalf("request url: %#v,and request: %#v", req.URL, req)
2644				return nil, nil
2645			}
2646		}),
2647	}
2648
2649	streams, _, buf, _ := genericclioptions.NewTestIOStreams()
2650	cmd := NewCmdGet("kubectl", tf, streams)
2651	cmd.SetOutput(buf)
2652
2653	cmd.Flags().Set("watch-only", "true")
2654	cmd.Run(cmd, []string{"pods"})
2655
2656	expected := `NAME   AGE
2657foo    <unknown>
2658foo    <unknown>
2659`
2660	if e, a := expected, buf.String(); e != a {
2661		t.Errorf("expected\n%v\ngot\n%v", e, a)
2662	}
2663}
2664
2665func TestWatchOnlyTableList(t *testing.T) {
2666	pods, events := watchTestData()
2667
2668	tf := cmdtesting.NewTestFactory().WithNamespace("test")
2669	defer tf.Cleanup()
2670	codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
2671
2672	podList := &corev1.PodList{
2673		Items: pods,
2674		ListMeta: metav1.ListMeta{
2675			ResourceVersion: "10",
2676		},
2677	}
2678	tf.UnstructuredClient = &fake.RESTClient{
2679		NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
2680		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
2681			switch req.URL.Path {
2682			case "/namespaces/test/pods":
2683				if req.URL.Query().Get("watch") == "true" {
2684					return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: podTableWatchBody(codec, events[2:])}, nil
2685				}
2686				return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: podTableObjBody(codec, podList.Items...)}, nil
2687			default:
2688				t.Fatalf("request url: %#v,and request: %#v", req.URL, req)
2689				return nil, nil
2690			}
2691		}),
2692	}
2693
2694	streams, _, buf, _ := genericclioptions.NewTestIOStreams()
2695	cmd := NewCmdGet("kubectl", tf, streams)
2696	cmd.SetOutput(buf)
2697
2698	cmd.Flags().Set("watch-only", "true")
2699	cmd.Run(cmd, []string{"pods"})
2700
2701	expected := `NAME   READY   STATUS   RESTARTS   AGE
2702foo    0/0              0          <unknown>
2703foo    0/0              0          <unknown>
2704`
2705	if e, a := expected, buf.String(); e != a {
2706		t.Errorf("expected\n%v\ngot\n%v", e, a)
2707	}
2708}
2709
2710func watchBody(codec runtime.Codec, events []watch.Event) io.ReadCloser {
2711	buf := bytes.NewBuffer([]byte{})
2712	enc := restclientwatch.NewEncoder(streaming.NewEncoder(buf, codec), codec)
2713	for i := range events {
2714		if err := enc.Encode(&events[i]); err != nil {
2715			panic(err)
2716		}
2717	}
2718	return ioutil.NopCloser(buf)
2719}
2720
2721var podColumns = []metav1.TableColumnDefinition{
2722	{Name: "Name", Type: "string", Format: "name"},
2723	{Name: "Ready", Type: "string", Format: ""},
2724	{Name: "Status", Type: "string", Format: ""},
2725	{Name: "Restarts", Type: "integer", Format: ""},
2726	{Name: "Age", Type: "string", Format: ""},
2727	{Name: "IP", Type: "string", Format: "", Priority: 1},
2728	{Name: "Node", Type: "string", Format: "", Priority: 1},
2729	{Name: "Nominated Node", Type: "string", Format: "", Priority: 1},
2730	{Name: "Readiness Gates", Type: "string", Format: "", Priority: 1},
2731}
2732
2733// build a meta table response from a pod list
2734func podTableObjBody(codec runtime.Codec, pods ...corev1.Pod) io.ReadCloser {
2735	table := &metav1beta1.Table{
2736		TypeMeta:          metav1.TypeMeta{APIVersion: "meta.k8s.io/v1beta1", Kind: "Table"},
2737		ColumnDefinitions: podColumns,
2738	}
2739	for i := range pods {
2740		b := bytes.NewBuffer(nil)
2741		codec.Encode(&pods[i], b)
2742		table.Rows = append(table.Rows, metav1beta1.TableRow{
2743			Object: runtime.RawExtension{Raw: b.Bytes()},
2744			Cells:  []interface{}{pods[i].Name, "0/0", "", int64(0), "<unknown>", "<none>", "<none>", "<none>", "<none>"},
2745		})
2746	}
2747	data, err := json.Marshal(table)
2748	if err != nil {
2749		panic(err)
2750	}
2751	if !strings.Contains(string(data), `"meta.k8s.io/v1beta1"`) {
2752		panic("expected v1beta1, got " + string(data))
2753	}
2754	return cmdtesting.BytesBody(data)
2755}
2756
2757// build a meta table response from a pod list
2758func podV1TableObjBody(codec runtime.Codec, pods ...corev1.Pod) io.ReadCloser {
2759	table := &metav1.Table{
2760		TypeMeta:          metav1.TypeMeta{APIVersion: "meta.k8s.io/v1", Kind: "Table"},
2761		ColumnDefinitions: podColumns,
2762	}
2763	for i := range pods {
2764		b := bytes.NewBuffer(nil)
2765		codec.Encode(&pods[i], b)
2766		table.Rows = append(table.Rows, metav1.TableRow{
2767			Object: runtime.RawExtension{Raw: b.Bytes()},
2768			Cells:  []interface{}{pods[i].Name, "0/0", "", int64(0), "<unknown>", "<none>", "<none>", "<none>", "<none>"},
2769		})
2770	}
2771	data, err := json.Marshal(table)
2772	if err != nil {
2773		panic(err)
2774	}
2775	if !strings.Contains(string(data), `"meta.k8s.io/v1"`) {
2776		panic("expected v1, got " + string(data))
2777	}
2778	return cmdtesting.BytesBody(data)
2779}
2780
2781// build meta table watch events from pod watch events
2782func podTableWatchBody(codec runtime.Codec, events []watch.Event) io.ReadCloser {
2783	tableEvents := []watch.Event{}
2784	for i, e := range events {
2785		b := bytes.NewBuffer(nil)
2786		codec.Encode(e.Object, b)
2787		var columns []metav1.TableColumnDefinition
2788		if i == 0 {
2789			columns = podColumns
2790		}
2791		tableEvents = append(tableEvents, watch.Event{
2792			Type: e.Type,
2793			Object: &metav1.Table{
2794				ColumnDefinitions: columns,
2795				Rows: []metav1.TableRow{{
2796					Object: runtime.RawExtension{Raw: b.Bytes()},
2797					Cells:  []interface{}{e.Object.(*corev1.Pod).Name, "0/0", "", int64(0), "<unknown>", "<none>", "<none>", "<none>", "<none>"},
2798				}}},
2799		})
2800	}
2801	return watchBody(codec, tableEvents)
2802}
2803
2804// build a meta table response from a service list
2805func serviceTableObjBody(codec runtime.Codec, services ...corev1.Service) io.ReadCloser {
2806	table := &metav1.Table{
2807		ColumnDefinitions: []metav1.TableColumnDefinition{
2808			{Name: "Name", Type: "string", Format: "name"},
2809			{Name: "Type", Type: "string", Format: ""},
2810			{Name: "Cluster-IP", Type: "string", Format: ""},
2811			{Name: "External-IP", Type: "string", Format: ""},
2812			{Name: "Port(s)", Type: "string", Format: ""},
2813			{Name: "Age", Type: "string", Format: ""},
2814		},
2815	}
2816	for i := range services {
2817		b := bytes.NewBuffer(nil)
2818		codec.Encode(&services[i], b)
2819		table.Rows = append(table.Rows, metav1.TableRow{
2820			Object: runtime.RawExtension{Raw: b.Bytes()},
2821			Cells:  []interface{}{services[i].Name, "ClusterIP", "<none>", "<none>", "<none>", "<unknown>"},
2822		})
2823	}
2824	return cmdtesting.ObjBody(codec, table)
2825}
2826
2827// build a meta table response from a node list
2828func nodeTableObjBody(codec runtime.Codec, nodes ...corev1.Node) io.ReadCloser {
2829	table := &metav1.Table{
2830		ColumnDefinitions: []metav1.TableColumnDefinition{
2831			{Name: "Name", Type: "string", Format: "name"},
2832			{Name: "Status", Type: "string", Format: ""},
2833			{Name: "Roles", Type: "string", Format: ""},
2834			{Name: "Age", Type: "string", Format: ""},
2835			{Name: "Version", Type: "string", Format: ""},
2836		},
2837	}
2838	for i := range nodes {
2839		b := bytes.NewBuffer(nil)
2840		codec.Encode(&nodes[i], b)
2841		table.Rows = append(table.Rows, metav1.TableRow{
2842			Object: runtime.RawExtension{Raw: b.Bytes()},
2843			Cells:  []interface{}{nodes[i].Name, "Unknown", "<none>", "<unknown>", ""},
2844		})
2845	}
2846	return cmdtesting.ObjBody(codec, table)
2847}
2848
2849// build a meta table response from a componentStatus list
2850func componentStatusTableObjBody(codec runtime.Codec, componentStatuses ...corev1.ComponentStatus) io.ReadCloser {
2851	table := &metav1.Table{
2852		ColumnDefinitions: []metav1.TableColumnDefinition{
2853			{Name: "Name", Type: "string", Format: "name"},
2854			{Name: "Status", Type: "string", Format: ""},
2855			{Name: "Message", Type: "string", Format: ""},
2856			{Name: "Error", Type: "string", Format: ""},
2857		},
2858	}
2859	for _, v := range componentStatuses {
2860		b := bytes.NewBuffer(nil)
2861		codec.Encode(&v, b)
2862		var status string
2863		if v.Conditions[0].Status == corev1.ConditionTrue {
2864			status = "Healthy"
2865		} else {
2866			status = "Unhealthy"
2867		}
2868		table.Rows = append(table.Rows, metav1.TableRow{
2869			Object: runtime.RawExtension{Raw: b.Bytes()},
2870			Cells:  []interface{}{v.Name, status, v.Conditions[0].Message, v.Conditions[0].Error},
2871		})
2872	}
2873	return cmdtesting.ObjBody(codec, table)
2874}
2875
2876// build an empty table response
2877func emptyTableObjBody(codec runtime.Codec) io.ReadCloser {
2878	table := &metav1.Table{
2879		ColumnDefinitions: podColumns,
2880	}
2881	return cmdtesting.ObjBody(codec, table)
2882}
2883