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