1
16
17 package internalversion
18
19 import (
20 "fmt"
21 "math"
22 "reflect"
23 "runtime"
24 "testing"
25 "time"
26
27 "github.com/google/go-cmp/cmp"
28 apiv1 "k8s.io/api/core/v1"
29 "k8s.io/apimachinery/pkg/api/resource"
30 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
31 "k8s.io/apimachinery/pkg/runtime/schema"
32 "k8s.io/apimachinery/pkg/util/intstr"
33 "k8s.io/client-go/util/certificate/csr"
34 "k8s.io/kubernetes/pkg/apis/admissionregistration"
35 "k8s.io/kubernetes/pkg/apis/apiserverinternal"
36 "k8s.io/kubernetes/pkg/apis/apps"
37 "k8s.io/kubernetes/pkg/apis/autoscaling"
38 "k8s.io/kubernetes/pkg/apis/batch"
39 "k8s.io/kubernetes/pkg/apis/certificates"
40 "k8s.io/kubernetes/pkg/apis/coordination"
41 api "k8s.io/kubernetes/pkg/apis/core"
42 "k8s.io/kubernetes/pkg/apis/discovery"
43 "k8s.io/kubernetes/pkg/apis/flowcontrol"
44 "k8s.io/kubernetes/pkg/apis/networking"
45 nodeapi "k8s.io/kubernetes/pkg/apis/node"
46 "k8s.io/kubernetes/pkg/apis/policy"
47 "k8s.io/kubernetes/pkg/apis/rbac"
48 "k8s.io/kubernetes/pkg/apis/scheduling"
49 "k8s.io/kubernetes/pkg/apis/storage"
50 "k8s.io/kubernetes/pkg/apis/storagemigration"
51 "k8s.io/kubernetes/pkg/printers"
52 utilpointer "k8s.io/utils/pointer"
53 )
54
55 var containerRestartPolicyAlways = api.ContainerRestartPolicyAlways
56
57 func TestFormatResourceName(t *testing.T) {
58 tests := []struct {
59 kind schema.GroupKind
60 name string
61 want string
62 }{
63 {schema.GroupKind{}, "", ""},
64 {schema.GroupKind{}, "name", "name"},
65 {schema.GroupKind{Kind: "Kind"}, "", "kind/"},
66 {schema.GroupKind{Kind: "Kind"}, "name", "kind/name"},
67 {schema.GroupKind{Group: "group", Kind: "Kind"}, "name", "kind.group/name"},
68 }
69 for _, tt := range tests {
70 if got := formatResourceName(tt.kind, tt.name, true); got != tt.want {
71 t.Errorf("formatResourceName(%q, %q) = %q, want %q", tt.kind, tt.name, got, tt.want)
72 }
73 }
74 }
75
76 type TestPrintHandler struct {
77 numCalls int
78 }
79
80 func (t *TestPrintHandler) TableHandler(columnDefinitions []metav1.TableColumnDefinition, printFunc interface{}) error {
81 t.numCalls++
82 return nil
83 }
84
85 func (t *TestPrintHandler) getNumCalls() int {
86 return t.numCalls
87 }
88
89 func TestAllHandlers(t *testing.T) {
90 h := &TestPrintHandler{numCalls: 0}
91 AddHandlers(h)
92 if h.getNumCalls() == 0 {
93 t.Error("TableHandler not called in AddHandlers")
94 }
95 }
96
97 func TestPrintEvent(t *testing.T) {
98 tests := []struct {
99 event api.Event
100 options printers.GenerateOptions
101 expected []metav1.TableRow
102 }{
103
104 {
105 event: api.Event{
106 Source: api.EventSource{Component: "kubelet"},
107 InvolvedObject: api.ObjectReference{
108 Kind: "Pod",
109 Name: "Pod Name",
110 FieldPath: "spec.containers{foo}",
111 },
112 Reason: "Event Reason",
113 Message: "Message Data",
114 FirstTimestamp: metav1.Time{Time: time.Now().UTC().AddDate(0, 0, -3)},
115 LastTimestamp: metav1.Time{Time: time.Now().UTC().AddDate(0, 0, -2)},
116 Count: 6,
117 Type: api.EventTypeNormal,
118 ObjectMeta: metav1.ObjectMeta{Name: "event1"},
119 },
120 options: printers.GenerateOptions{},
121
122 expected: []metav1.TableRow{{Cells: []interface{}{"2d", "Normal", "Event Reason", "pod/Pod Name", "Message Data"}}},
123 },
124
125 {
126 event: api.Event{
127 Source: api.EventSource{
128 Component: "kubelet",
129 Host: "Node1",
130 },
131 InvolvedObject: api.ObjectReference{
132 Kind: "Deployment",
133 Name: "Deployment Name",
134 FieldPath: "spec.containers{foo}",
135 },
136 Reason: "Event Reason",
137 Message: "Message Data",
138 FirstTimestamp: metav1.Time{Time: time.Now().UTC().AddDate(0, 0, -3)},
139 LastTimestamp: metav1.Time{Time: time.Now().UTC().AddDate(0, 0, -2)},
140 Count: 6,
141 Type: api.EventTypeWarning,
142 ObjectMeta: metav1.ObjectMeta{Name: "event2"},
143 },
144 options: printers.GenerateOptions{Wide: true},
145
146 expected: []metav1.TableRow{{Cells: []interface{}{"2d", "Warning", "Event Reason", "deployment/Deployment Name", "spec.containers{foo}", "kubelet, Node1", "Message Data", "3d", int64(6), "event2"}}},
147 },
148
149 {
150 event: api.Event{
151 Source: api.EventSource{
152 Component: "kubelet",
153 Host: "Node1",
154 },
155 InvolvedObject: api.ObjectReference{
156 Kind: "Deployment",
157 Name: "Deployment Name",
158 FieldPath: "spec.containers{foo}",
159 },
160 Reason: "Event Reason",
161 Message: "Message Data",
162 EventTime: metav1.MicroTime{Time: time.Now().UTC().AddDate(0, 0, -3)},
163 LastTimestamp: metav1.Time{Time: time.Now().UTC().AddDate(0, 0, -3)},
164 Count: 1,
165 Type: api.EventTypeWarning,
166 ObjectMeta: metav1.ObjectMeta{Name: "event3"},
167 },
168 options: printers.GenerateOptions{Wide: true},
169
170 expected: []metav1.TableRow{{Cells: []interface{}{"3d", "Warning", "Event Reason", "deployment/Deployment Name", "spec.containers{foo}", "kubelet, Node1", "Message Data", "3d", int64(1), "event3"}}},
171 },
172
173 {
174 event: api.Event{
175 Source: api.EventSource{
176 Component: "kubelet",
177 Host: "Node1",
178 },
179 InvolvedObject: api.ObjectReference{
180 Kind: "Deployment",
181 Name: "Deployment Name",
182 FieldPath: "spec.containers{foo}",
183 },
184 Reason: "Event Reason",
185 Message: "Message Data",
186 EventTime: metav1.MicroTime{Time: time.Now().UTC().AddDate(0, 0, -3)},
187 FirstTimestamp: metav1.Time{Time: time.Now().UTC().AddDate(0, 0, -3)},
188 Count: 1,
189 Type: api.EventTypeWarning,
190 ObjectMeta: metav1.ObjectMeta{Name: "event4"},
191 },
192 options: printers.GenerateOptions{Wide: true},
193
194 expected: []metav1.TableRow{{Cells: []interface{}{"3d", "Warning", "Event Reason", "deployment/Deployment Name", "spec.containers{foo}", "kubelet, Node1", "Message Data", "3d", int64(1), "event4"}}},
195 },
196
197 {
198 event: api.Event{
199 Source: api.EventSource{
200 Component: "kubelet",
201 Host: "Node1",
202 },
203 InvolvedObject: api.ObjectReference{
204 Kind: "Deployment",
205 Name: "Deployment Name",
206 FieldPath: "spec.containers{foo}",
207 },
208 Reason: "Event Reason",
209 Message: "Message Data",
210 EventTime: metav1.MicroTime{Time: time.Now().UTC().AddDate(0, 0, -3)},
211 Count: 1,
212 Type: api.EventTypeWarning,
213 ObjectMeta: metav1.ObjectMeta{Name: "event5"},
214 },
215 options: printers.GenerateOptions{Wide: true},
216
217 expected: []metav1.TableRow{{Cells: []interface{}{"3d", "Warning", "Event Reason", "deployment/Deployment Name", "spec.containers{foo}", "kubelet, Node1", "Message Data", "3d", int64(1), "event5"}}},
218 },
219
220 {
221 event: api.Event{
222 Source: api.EventSource{
223 Component: "kubelet",
224 Host: "Node1",
225 },
226 InvolvedObject: api.ObjectReference{
227 Kind: "Deployment",
228 Name: "Deployment Name",
229 FieldPath: "spec.containers{foo}",
230 },
231 Series: &api.EventSeries{
232 Count: 2,
233 LastObservedTime: metav1.MicroTime{Time: time.Now().UTC().AddDate(0, 0, -2)},
234 },
235 Reason: "Event Reason",
236 Message: "Message Data",
237 EventTime: metav1.MicroTime{Time: time.Now().UTC().AddDate(0, 0, -3)},
238 Type: api.EventTypeWarning,
239 ObjectMeta: metav1.ObjectMeta{Name: "event6"},
240 },
241 options: printers.GenerateOptions{Wide: true},
242
243 expected: []metav1.TableRow{{Cells: []interface{}{"2d", "Warning", "Event Reason", "deployment/Deployment Name", "spec.containers{foo}", "kubelet, Node1", "Message Data", "3d", int64(2), "event6"}}},
244 },
245
246 {
247 event: api.Event{
248 Source: api.EventSource{
249 Component: "kubelet",
250 Host: "Node1",
251 },
252 InvolvedObject: api.ObjectReference{
253 Kind: "Deployment",
254 Name: "Deployment Name",
255 FieldPath: "spec.containers{foo}",
256 },
257 Reason: "Event Reason",
258 Message: "Message Data",
259 EventTime: metav1.MicroTime{Time: time.Now().UTC().AddDate(0, 0, -3)},
260 Type: api.EventTypeWarning,
261 ObjectMeta: metav1.ObjectMeta{Name: "event7"},
262 },
263 options: printers.GenerateOptions{Wide: true},
264
265 expected: []metav1.TableRow{{Cells: []interface{}{"3d", "Warning", "Event Reason", "deployment/Deployment Name", "spec.containers{foo}", "kubelet, Node1", "Message Data", "3d", int64(1), "event7"}}},
266 },
267
268 {
269 event: api.Event{
270 ReportingController: "kubelet",
271 ReportingInstance: "test",
272 InvolvedObject: api.ObjectReference{
273 Kind: "Deployment",
274 Name: "Deployment Name",
275 FieldPath: "spec.containers{foo}",
276 },
277 Reason: "Event Reason",
278 Message: "Message Data",
279 FirstTimestamp: metav1.Time{Time: time.Now().UTC().AddDate(0, 0, -3)},
280 LastTimestamp: metav1.Time{Time: time.Now().UTC().AddDate(0, 0, -2)},
281 Count: 6,
282 Type: api.EventTypeWarning,
283 ObjectMeta: metav1.ObjectMeta{Name: "event2"},
284 },
285 options: printers.GenerateOptions{Wide: true},
286
287 expected: []metav1.TableRow{{Cells: []interface{}{"2d", "Warning", "Event Reason", "deployment/Deployment Name", "spec.containers{foo}", "kubelet, test", "Message Data", "3d", int64(6), "event2"}}},
288 },
289 }
290
291 for i, test := range tests {
292 rows, err := printEvent(&test.event, test.options)
293 if err != nil {
294 t.Fatal(err)
295 }
296 for i := range rows {
297 rows[i].Object.Object = nil
298 }
299 if !reflect.DeepEqual(test.expected, rows) {
300 t.Errorf("%d mismatch: %s", i, cmp.Diff(test.expected, rows))
301 }
302 }
303 }
304
305 func TestPrintEventsResultSorted(t *testing.T) {
306
307 eventList := api.EventList{
308 Items: []api.Event{
309 {
310 Source: api.EventSource{Component: "kubelet"},
311 Message: "Item 1",
312 FirstTimestamp: metav1.NewTime(time.Date(2014, time.January, 15, 0, 0, 0, 0, time.UTC)),
313 LastTimestamp: metav1.NewTime(time.Date(2014, time.January, 15, 0, 0, 0, 0, time.UTC)),
314 Count: 1,
315 Type: api.EventTypeNormal,
316 },
317 {
318 Source: api.EventSource{Component: "scheduler"},
319 Message: "Item 2",
320 FirstTimestamp: metav1.NewTime(time.Date(1987, time.June, 17, 0, 0, 0, 0, time.UTC)),
321 LastTimestamp: metav1.NewTime(time.Date(1987, time.June, 17, 0, 0, 0, 0, time.UTC)),
322 Count: 1,
323 Type: api.EventTypeNormal,
324 },
325 {
326 Source: api.EventSource{Component: "kubelet"},
327 Message: "Item 3",
328 FirstTimestamp: metav1.NewTime(time.Date(2002, time.December, 25, 0, 0, 0, 0, time.UTC)),
329 LastTimestamp: metav1.NewTime(time.Date(2002, time.December, 25, 0, 0, 0, 0, time.UTC)),
330 Count: 1,
331 Type: api.EventTypeNormal,
332 },
333 },
334 }
335
336 rows, err := printEventList(&eventList, printers.GenerateOptions{})
337 if err != nil {
338 t.Fatal(err)
339 }
340 if len(rows) != 3 {
341 t.Errorf("Generate Event List: Wrong number of table rows returned. Expected 3, got (%d)", len(rows))
342 }
343
344 firstRow := rows[0]
345 message1 := firstRow.Cells[4]
346 if message1.(string) != "Item 1" {
347 t.Errorf("Wrong event ordering: expecting (Item 1), got (%s)", message1)
348 }
349 secondRow := rows[1]
350 message2 := secondRow.Cells[4]
351 if message2 != "Item 2" {
352 t.Errorf("Wrong event ordering: expecting (Item 2), got (%s)", message2)
353 }
354 thirdRow := rows[2]
355 message3 := thirdRow.Cells[4]
356 if message3 != "Item 3" {
357 t.Errorf("Wrong event ordering: expecting (Item 3), got (%s)", message3)
358 }
359 }
360
361 func TestPrintNamespace(t *testing.T) {
362 tests := []struct {
363 namespace api.Namespace
364 expected []metav1.TableRow
365 }{
366
367 {
368 namespace: api.Namespace{
369 ObjectMeta: metav1.ObjectMeta{
370 Name: "namespace1",
371 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
372 },
373 Status: api.NamespaceStatus{
374 Phase: "FooStatus",
375 },
376 },
377
378 expected: []metav1.TableRow{{Cells: []interface{}{"namespace1", "FooStatus", "0s"}}},
379 },
380
381 {
382 namespace: api.Namespace{
383 ObjectMeta: metav1.ObjectMeta{
384 Name: "namespace2",
385 },
386 },
387
388 expected: []metav1.TableRow{{Cells: []interface{}{"namespace2", "", "<unknown>"}}},
389 },
390 }
391
392 for i, test := range tests {
393 rows, err := printNamespace(&test.namespace, printers.GenerateOptions{})
394 if err != nil {
395 t.Fatal(err)
396 }
397 for i := range rows {
398 rows[i].Object.Object = nil
399 }
400 if !reflect.DeepEqual(test.expected, rows) {
401 t.Errorf("%d mismatch: %s", i, cmp.Diff(test.expected, rows))
402 }
403 }
404 }
405
406 func TestPrintSecret(t *testing.T) {
407 tests := []struct {
408 secret api.Secret
409 expected []metav1.TableRow
410 }{
411
412 {
413 secret: api.Secret{
414 ObjectMeta: metav1.ObjectMeta{
415 Name: "secret1",
416 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
417 },
418 Type: "kubernetes.io/service-account-token",
419 Data: map[string][]byte{
420 "token": []byte("secret data"),
421 },
422 },
423
424 expected: []metav1.TableRow{{Cells: []interface{}{"secret1", "kubernetes.io/service-account-token", int64(1), "0s"}}},
425 },
426
427 {
428 secret: api.Secret{
429 ObjectMeta: metav1.ObjectMeta{
430 Name: "secret1",
431 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
432 },
433 Type: "kubernetes.io/service-account-token",
434 },
435
436 expected: []metav1.TableRow{{Cells: []interface{}{"secret1", "kubernetes.io/service-account-token", int64(0), "0s"}}},
437 },
438 }
439
440 for i, test := range tests {
441 rows, err := printSecret(&test.secret, printers.GenerateOptions{})
442 if err != nil {
443 t.Fatal(err)
444 }
445 for i := range rows {
446 rows[i].Object.Object = nil
447 }
448 if !reflect.DeepEqual(test.expected, rows) {
449 t.Errorf("%d mismatch: %s", i, cmp.Diff(test.expected, rows))
450 }
451 }
452 }
453
454 func TestPrintServiceAccount(t *testing.T) {
455 tests := []struct {
456 serviceAccount api.ServiceAccount
457 expected []metav1.TableRow
458 }{
459
460 {
461 serviceAccount: api.ServiceAccount{
462 ObjectMeta: metav1.ObjectMeta{
463 Name: "sa1",
464 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
465 },
466 Secrets: []api.ObjectReference{},
467 },
468
469 expected: []metav1.TableRow{{Cells: []interface{}{"sa1", int64(0), "0s"}}},
470 },
471
472 {
473 serviceAccount: api.ServiceAccount{
474 ObjectMeta: metav1.ObjectMeta{
475 Name: "sa1",
476 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
477 },
478 Secrets: []api.ObjectReference{
479 {Name: "Secret1"},
480 {Name: "Secret2"},
481 },
482 },
483
484 expected: []metav1.TableRow{{Cells: []interface{}{"sa1", int64(2), "0s"}}},
485 },
486 }
487
488 for i, test := range tests {
489 rows, err := printServiceAccount(&test.serviceAccount, printers.GenerateOptions{})
490 if err != nil {
491 t.Fatal(err)
492 }
493 for i := range rows {
494 rows[i].Object.Object = nil
495 }
496 if !reflect.DeepEqual(test.expected, rows) {
497 t.Errorf("%d mismatch: %s", i, cmp.Diff(test.expected, rows))
498 }
499 }
500 }
501
502 func TestPrintNodeStatus(t *testing.T) {
503
504 table := []struct {
505 node api.Node
506 expected []metav1.TableRow
507 }{
508 {
509 node: api.Node{
510 ObjectMeta: metav1.ObjectMeta{Name: "foo1"},
511 Status: api.NodeStatus{Conditions: []api.NodeCondition{{Type: api.NodeReady, Status: api.ConditionTrue}}},
512 },
513
514 expected: []metav1.TableRow{{Cells: []interface{}{"foo1", "Ready", "<none>", "<unknown>", ""}}},
515 },
516 {
517 node: api.Node{
518 ObjectMeta: metav1.ObjectMeta{Name: "foo2"},
519 Spec: api.NodeSpec{Unschedulable: true},
520 Status: api.NodeStatus{Conditions: []api.NodeCondition{{Type: api.NodeReady, Status: api.ConditionTrue}}},
521 },
522
523 expected: []metav1.TableRow{{Cells: []interface{}{"foo2", "Ready,SchedulingDisabled", "<none>", "<unknown>", ""}}},
524 },
525 {
526 node: api.Node{
527 ObjectMeta: metav1.ObjectMeta{Name: "foo3"},
528 Status: api.NodeStatus{Conditions: []api.NodeCondition{
529 {Type: api.NodeReady, Status: api.ConditionTrue},
530 {Type: api.NodeReady, Status: api.ConditionTrue}}},
531 },
532
533 expected: []metav1.TableRow{{Cells: []interface{}{"foo3", "Ready", "<none>", "<unknown>", ""}}},
534 },
535 {
536 node: api.Node{
537 ObjectMeta: metav1.ObjectMeta{Name: "foo4"},
538 Status: api.NodeStatus{Conditions: []api.NodeCondition{{Type: api.NodeReady, Status: api.ConditionFalse}}},
539 },
540
541 expected: []metav1.TableRow{{Cells: []interface{}{"foo4", "NotReady", "<none>", "<unknown>", ""}}},
542 },
543 {
544 node: api.Node{
545 ObjectMeta: metav1.ObjectMeta{Name: "foo5"},
546 Spec: api.NodeSpec{Unschedulable: true},
547 Status: api.NodeStatus{Conditions: []api.NodeCondition{{Type: api.NodeReady, Status: api.ConditionFalse}}},
548 },
549
550 expected: []metav1.TableRow{{Cells: []interface{}{"foo5", "NotReady,SchedulingDisabled", "<none>", "<unknown>", ""}}},
551 },
552 {
553 node: api.Node{
554 ObjectMeta: metav1.ObjectMeta{Name: "foo6"},
555 Status: api.NodeStatus{Conditions: []api.NodeCondition{{Type: "InvalidValue", Status: api.ConditionTrue}}},
556 },
557
558 expected: []metav1.TableRow{{Cells: []interface{}{"foo6", "Unknown", "<none>", "<unknown>", ""}}},
559 },
560 {
561 node: api.Node{
562 ObjectMeta: metav1.ObjectMeta{Name: "foo7"},
563 Status: api.NodeStatus{Conditions: []api.NodeCondition{{}}},
564 },
565
566 expected: []metav1.TableRow{{Cells: []interface{}{"foo7", "Unknown", "<none>", "<unknown>", ""}}},
567 },
568 {
569 node: api.Node{
570 ObjectMeta: metav1.ObjectMeta{Name: "foo8"},
571 Spec: api.NodeSpec{Unschedulable: true},
572 Status: api.NodeStatus{Conditions: []api.NodeCondition{{Type: "InvalidValue", Status: api.ConditionTrue}}},
573 },
574
575 expected: []metav1.TableRow{{Cells: []interface{}{"foo8", "Unknown,SchedulingDisabled", "<none>", "<unknown>", ""}}},
576 },
577 {
578 node: api.Node{
579 ObjectMeta: metav1.ObjectMeta{Name: "foo9"},
580 Spec: api.NodeSpec{Unschedulable: true},
581 Status: api.NodeStatus{Conditions: []api.NodeCondition{{}}},
582 },
583
584 expected: []metav1.TableRow{{Cells: []interface{}{"foo9", "Unknown,SchedulingDisabled", "<none>", "<unknown>", ""}}},
585 },
586 }
587
588 for i, test := range table {
589 rows, err := printNode(&test.node, printers.GenerateOptions{})
590 if err != nil {
591 t.Fatalf("Error generating table rows for Node: %#v", err)
592 }
593 for i := range rows {
594 rows[i].Object.Object = nil
595 }
596 if !reflect.DeepEqual(test.expected, rows) {
597 t.Errorf("%d mismatch: %s", i, cmp.Diff(test.expected, rows))
598 }
599 }
600 }
601
602 func TestPrintNodeRole(t *testing.T) {
603
604 table := []struct {
605 node api.Node
606 expected []metav1.TableRow
607 }{
608 {
609 node: api.Node{
610 ObjectMeta: metav1.ObjectMeta{Name: "foo9"},
611 },
612
613 expected: []metav1.TableRow{{Cells: []interface{}{"foo9", "Unknown", "<none>", "<unknown>", ""}}},
614 },
615 {
616 node: api.Node{
617 ObjectMeta: metav1.ObjectMeta{
618 Name: "foo10",
619 Labels: map[string]string{"node-role.kubernetes.io/master": "", "node-role.kubernetes.io/control-plane": "", "node-role.kubernetes.io/proxy": "", "kubernetes.io/role": "node"},
620 },
621 },
622
623 expected: []metav1.TableRow{{Cells: []interface{}{"foo10", "Unknown", "control-plane,master,node,proxy", "<unknown>", ""}}},
624 },
625 {
626 node: api.Node{
627 ObjectMeta: metav1.ObjectMeta{
628 Name: "foo11",
629 Labels: map[string]string{"kubernetes.io/role": "node"},
630 },
631 },
632
633 expected: []metav1.TableRow{{Cells: []interface{}{"foo11", "Unknown", "node", "<unknown>", ""}}},
634 },
635 }
636
637 for i, test := range table {
638 rows, err := printNode(&test.node, printers.GenerateOptions{})
639 if err != nil {
640 t.Fatalf("An error occurred generating table rows for Node: %#v", err)
641 }
642 for i := range rows {
643 rows[i].Object.Object = nil
644 }
645 if !reflect.DeepEqual(test.expected, rows) {
646 t.Errorf("%d mismatch: %s", i, cmp.Diff(test.expected, rows))
647 }
648 }
649 }
650
651 func TestPrintNodeOSImage(t *testing.T) {
652
653 table := []struct {
654 node api.Node
655 expected []metav1.TableRow
656 }{
657 {
658 node: api.Node{
659 ObjectMeta: metav1.ObjectMeta{Name: "foo1"},
660 Status: api.NodeStatus{
661 NodeInfo: api.NodeSystemInfo{OSImage: "fake-os-image"},
662 Addresses: []api.NodeAddress{{Type: api.NodeExternalIP, Address: "1.1.1.1"}},
663 },
664 },
665
666 expected: []metav1.TableRow{
667 {
668 Cells: []interface{}{"foo1", "Unknown", "<none>", "<unknown>", "", "<none>", "1.1.1.1", "fake-os-image", "<unknown>", "<unknown>"},
669 },
670 },
671 },
672 {
673 node: api.Node{
674 ObjectMeta: metav1.ObjectMeta{Name: "foo2"},
675 Status: api.NodeStatus{
676 NodeInfo: api.NodeSystemInfo{KernelVersion: "fake-kernel-version"},
677 Addresses: []api.NodeAddress{{Type: api.NodeExternalIP, Address: "1.1.1.1"}},
678 },
679 },
680
681 expected: []metav1.TableRow{
682 {
683 Cells: []interface{}{"foo2", "Unknown", "<none>", "<unknown>", "", "<none>", "1.1.1.1", "<unknown>", "fake-kernel-version", "<unknown>"},
684 },
685 },
686 },
687 }
688
689 for i, test := range table {
690 rows, err := printNode(&test.node, printers.GenerateOptions{Wide: true})
691 if err != nil {
692 t.Fatalf("An error occurred generating table for Node: %#v", err)
693 }
694 for i := range rows {
695 rows[i].Object.Object = nil
696 }
697 if !reflect.DeepEqual(test.expected, rows) {
698 t.Errorf("%d mismatch: %s", i, cmp.Diff(test.expected, rows))
699 }
700 }
701 }
702
703 func TestPrintNodeKernelVersion(t *testing.T) {
704
705 table := []struct {
706 node api.Node
707 expected []metav1.TableRow
708 }{
709 {
710 node: api.Node{
711 ObjectMeta: metav1.ObjectMeta{Name: "foo1"},
712 Status: api.NodeStatus{
713 NodeInfo: api.NodeSystemInfo{KernelVersion: "fake-kernel-version"},
714 Addresses: []api.NodeAddress{{Type: api.NodeExternalIP, Address: "1.1.1.1"}},
715 },
716 },
717
718 expected: []metav1.TableRow{
719 {
720 Cells: []interface{}{"foo1", "Unknown", "<none>", "<unknown>", "", "<none>", "1.1.1.1", "<unknown>", "fake-kernel-version", "<unknown>"},
721 },
722 },
723 },
724 {
725 node: api.Node{
726 ObjectMeta: metav1.ObjectMeta{Name: "foo2"},
727 Status: api.NodeStatus{
728 NodeInfo: api.NodeSystemInfo{OSImage: "fake-os-image"},
729 Addresses: []api.NodeAddress{{Type: api.NodeExternalIP, Address: "1.1.1.1"}},
730 },
731 },
732
733 expected: []metav1.TableRow{
734 {
735 Cells: []interface{}{"foo2", "Unknown", "<none>", "<unknown>", "", "<none>", "1.1.1.1", "fake-os-image", "<unknown>", "<unknown>"},
736 },
737 },
738 },
739 }
740
741 for i, test := range table {
742 rows, err := printNode(&test.node, printers.GenerateOptions{Wide: true})
743 if err != nil {
744 t.Fatalf("An error occurred generating table rows Node: %#v", err)
745 }
746 for i := range rows {
747 rows[i].Object.Object = nil
748 }
749 if !reflect.DeepEqual(test.expected, rows) {
750 t.Errorf("%d mismatch: %s", i, cmp.Diff(test.expected, rows))
751 }
752 }
753 }
754
755 func TestPrintNodeContainerRuntimeVersion(t *testing.T) {
756
757 table := []struct {
758 node api.Node
759 expected []metav1.TableRow
760 }{
761 {
762 node: api.Node{
763 ObjectMeta: metav1.ObjectMeta{Name: "foo1"},
764 Status: api.NodeStatus{
765 NodeInfo: api.NodeSystemInfo{ContainerRuntimeVersion: "foo://1.2.3"},
766 Addresses: []api.NodeAddress{{Type: api.NodeExternalIP, Address: "1.1.1.1"}},
767 },
768 },
769
770 expected: []metav1.TableRow{
771 {
772 Cells: []interface{}{"foo1", "Unknown", "<none>", "<unknown>", "", "<none>", "1.1.1.1", "<unknown>", "<unknown>", "foo://1.2.3"},
773 },
774 },
775 },
776 {
777 node: api.Node{
778 ObjectMeta: metav1.ObjectMeta{Name: "foo2"},
779 Status: api.NodeStatus{
780 NodeInfo: api.NodeSystemInfo{},
781 Addresses: []api.NodeAddress{{Type: api.NodeExternalIP, Address: "1.1.1.1"}},
782 },
783 },
784
785 expected: []metav1.TableRow{
786 {
787 Cells: []interface{}{"foo2", "Unknown", "<none>", "<unknown>", "", "<none>", "1.1.1.1", "<unknown>", "<unknown>", "<unknown>"},
788 },
789 },
790 },
791 }
792
793 for i, test := range table {
794 rows, err := printNode(&test.node, printers.GenerateOptions{Wide: true})
795 if err != nil {
796 t.Fatalf("An error occurred generating table rows Node: %#v", err)
797 }
798 for i := range rows {
799 rows[i].Object.Object = nil
800 }
801 if !reflect.DeepEqual(test.expected, rows) {
802 t.Errorf("%d mismatch: %s", i, cmp.Diff(test.expected, rows))
803 }
804 }
805 }
806
807 func TestPrintNodeName(t *testing.T) {
808
809 table := []struct {
810 node api.Node
811 expected []metav1.TableRow
812 }{
813 {
814 node: api.Node{
815 ObjectMeta: metav1.ObjectMeta{Name: "127.0.0.1"},
816 Status: api.NodeStatus{},
817 },
818
819 expected: []metav1.TableRow{{Cells: []interface{}{"127.0.0.1", "Unknown", "<none>", "<unknown>", ""}}}},
820 {
821 node: api.Node{
822 ObjectMeta: metav1.ObjectMeta{Name: ""},
823 Status: api.NodeStatus{},
824 },
825
826 expected: []metav1.TableRow{{Cells: []interface{}{"", "Unknown", "<none>", "<unknown>", ""}}},
827 },
828 }
829
830 for i, test := range table {
831 rows, err := printNode(&test.node, printers.GenerateOptions{})
832 if err != nil {
833 t.Fatalf("An error occurred generating table rows Node: %#v", err)
834 }
835 for i := range rows {
836 rows[i].Object.Object = nil
837 }
838 if !reflect.DeepEqual(test.expected, rows) {
839 t.Errorf("%d mismatch: %s", i, cmp.Diff(test.expected, rows))
840 }
841 }
842 }
843
844 func TestPrintNodeExternalIP(t *testing.T) {
845
846 table := []struct {
847 node api.Node
848 expected []metav1.TableRow
849 }{
850 {
851 node: api.Node{
852 ObjectMeta: metav1.ObjectMeta{Name: "foo1"},
853 Status: api.NodeStatus{Addresses: []api.NodeAddress{{Type: api.NodeExternalIP, Address: "1.1.1.1"}}},
854 },
855
856 expected: []metav1.TableRow{
857 {
858 Cells: []interface{}{"foo1", "Unknown", "<none>", "<unknown>", "", "<none>", "1.1.1.1", "<unknown>", "<unknown>", "<unknown>"},
859 },
860 },
861 },
862 {
863 node: api.Node{
864 ObjectMeta: metav1.ObjectMeta{Name: "foo2"},
865 Status: api.NodeStatus{Addresses: []api.NodeAddress{{Type: api.NodeInternalIP, Address: "1.1.1.1"}}},
866 },
867
868 expected: []metav1.TableRow{
869 {
870 Cells: []interface{}{"foo2", "Unknown", "<none>", "<unknown>", "", "1.1.1.1", "<none>", "<unknown>", "<unknown>", "<unknown>"},
871 },
872 },
873 },
874 {
875 node: api.Node{
876 ObjectMeta: metav1.ObjectMeta{Name: "foo3"},
877 Status: api.NodeStatus{Addresses: []api.NodeAddress{
878 {Type: api.NodeExternalIP, Address: "2.2.2.2"},
879 {Type: api.NodeInternalIP, Address: "3.3.3.3"},
880 {Type: api.NodeExternalIP, Address: "4.4.4.4"},
881 }},
882 },
883 expected: []metav1.TableRow{
884 {
885 Cells: []interface{}{"foo3", "Unknown", "<none>", "<unknown>", "", "3.3.3.3", "2.2.2.2", "<unknown>", "<unknown>", "<unknown>"},
886 },
887 },
888 },
889 }
890
891 for i, test := range table {
892 rows, err := printNode(&test.node, printers.GenerateOptions{Wide: true})
893 if err != nil {
894 t.Fatalf("An error occurred generating table rows Node: %#v", err)
895 }
896 for i := range rows {
897 rows[i].Object.Object = nil
898 }
899 if !reflect.DeepEqual(test.expected, rows) {
900 t.Errorf("%d mismatch: %s", i, cmp.Diff(test.expected, rows))
901 }
902 }
903 }
904
905 func TestPrintNodeInternalIP(t *testing.T) {
906
907 table := []struct {
908 node api.Node
909 expected []metav1.TableRow
910 }{
911 {
912 node: api.Node{
913 ObjectMeta: metav1.ObjectMeta{Name: "foo1"},
914 Status: api.NodeStatus{Addresses: []api.NodeAddress{{Type: api.NodeInternalIP, Address: "1.1.1.1"}}},
915 },
916
917 expected: []metav1.TableRow{
918 {
919 Cells: []interface{}{"foo1", "Unknown", "<none>", "<unknown>", "", "1.1.1.1", "<none>", "<unknown>", "<unknown>", "<unknown>"},
920 },
921 },
922 },
923 {
924 node: api.Node{
925 ObjectMeta: metav1.ObjectMeta{Name: "foo2"},
926 Status: api.NodeStatus{Addresses: []api.NodeAddress{{Type: api.NodeExternalIP, Address: "1.1.1.1"}}},
927 },
928
929 expected: []metav1.TableRow{
930 {
931 Cells: []interface{}{"foo2", "Unknown", "<none>", "<unknown>", "", "<none>", "1.1.1.1", "<unknown>", "<unknown>", "<unknown>"},
932 },
933 },
934 },
935 {
936 node: api.Node{
937 ObjectMeta: metav1.ObjectMeta{Name: "foo3"},
938 Status: api.NodeStatus{Addresses: []api.NodeAddress{
939 {Type: api.NodeInternalIP, Address: "2.2.2.2"},
940 {Type: api.NodeExternalIP, Address: "3.3.3.3"},
941 {Type: api.NodeInternalIP, Address: "4.4.4.4"},
942 }},
943 },
944
945 expected: []metav1.TableRow{
946 {
947 Cells: []interface{}{"foo3", "Unknown", "<none>", "<unknown>", "", "2.2.2.2", "3.3.3.3", "<unknown>", "<unknown>", "<unknown>"},
948 },
949 },
950 },
951 }
952
953 for i, test := range table {
954 rows, err := printNode(&test.node, printers.GenerateOptions{Wide: true})
955 if err != nil {
956 t.Fatalf("An error occurred generating table rows Node: %#v", err)
957 }
958 for i := range rows {
959 rows[i].Object.Object = nil
960 }
961 if !reflect.DeepEqual(test.expected, rows) {
962 t.Errorf("%d mismatch: %s", i, cmp.Diff(test.expected, rows))
963 }
964 }
965 }
966
967 func TestPrintIngress(t *testing.T) {
968 ingress := networking.Ingress{
969 ObjectMeta: metav1.ObjectMeta{
970 Name: "test1",
971 CreationTimestamp: metav1.Time{Time: time.Now().AddDate(-10, 0, 0)},
972 },
973 Spec: networking.IngressSpec{
974 IngressClassName: utilpointer.StringPtr("foo"),
975 DefaultBackend: &networking.IngressBackend{
976 Service: &networking.IngressServiceBackend{
977 Name: "default-backend",
978 Port: networking.ServiceBackendPort{
979 Name: "default-backend",
980 Number: 80,
981 },
982 },
983 },
984 },
985 Status: networking.IngressStatus{
986 LoadBalancer: networking.IngressLoadBalancerStatus{
987 Ingress: []networking.IngressLoadBalancerIngress{
988 {
989 IP: "2.3.4.5",
990 Hostname: "localhost.localdomain",
991 },
992 },
993 },
994 },
995 }
996
997 expected := []metav1.TableRow{{Cells: []interface{}{"test1", "foo", "*", "2.3.4.5", "80", "10y"}}}
998
999 rows, err := printIngress(&ingress, printers.GenerateOptions{})
1000 if err != nil {
1001 t.Fatalf("Error generating table rows for Ingress: %#v", err)
1002 }
1003 rows[0].Object.Object = nil
1004 if !reflect.DeepEqual(expected, rows) {
1005 t.Errorf("mismatch: %s", cmp.Diff(expected, rows))
1006 }
1007 }
1008
1009 func TestPrintIngressClass(t *testing.T) {
1010 testCases := []struct {
1011 name string
1012 ingressClass *networking.IngressClass
1013 expected []metav1.TableRow
1014 }{{
1015 name: "example with params",
1016 ingressClass: &networking.IngressClass{
1017 ObjectMeta: metav1.ObjectMeta{
1018 Name: "test1",
1019 CreationTimestamp: metav1.Time{Time: time.Now().AddDate(-10, 0, 0)},
1020 },
1021 Spec: networking.IngressClassSpec{
1022 Controller: "example.com/controller",
1023 Parameters: &networking.IngressClassParametersReference{Kind: "customgroup", Name: "example"},
1024 },
1025 },
1026 expected: []metav1.TableRow{{Cells: []interface{}{"test1", "example.com/controller", "customgroup/example", "10y"}}},
1027 }, {
1028 name: "example with params + API Group",
1029 ingressClass: &networking.IngressClass{
1030 ObjectMeta: metav1.ObjectMeta{
1031 Name: "test1",
1032 CreationTimestamp: metav1.Time{Time: time.Now().AddDate(-10, 0, 0)},
1033 },
1034 Spec: networking.IngressClassSpec{
1035 Controller: "example.com/controller",
1036 Parameters: &networking.IngressClassParametersReference{
1037 APIGroup: utilpointer.StringPtr("example.com"),
1038 Kind: "customgroup",
1039 Name: "example",
1040 },
1041 },
1042 },
1043 expected: []metav1.TableRow{{Cells: []interface{}{"test1", "example.com/controller", "customgroup.example.com/example", "10y"}}},
1044 }, {
1045 name: "example without params",
1046 ingressClass: &networking.IngressClass{
1047 ObjectMeta: metav1.ObjectMeta{
1048 Name: "test2",
1049 CreationTimestamp: metav1.Time{Time: time.Now().AddDate(-11, 0, 0)},
1050 },
1051 Spec: networking.IngressClassSpec{
1052 Controller: "example.com/controller2",
1053 },
1054 },
1055 expected: []metav1.TableRow{{Cells: []interface{}{"test2", "example.com/controller2", "<none>", "11y"}}},
1056 }}
1057
1058 for _, testCase := range testCases {
1059 t.Run(testCase.name, func(t *testing.T) {
1060 rows, err := printIngressClass(testCase.ingressClass, printers.GenerateOptions{})
1061 if err != nil {
1062 t.Fatalf("Error generating table rows for Ingress: %#v", err)
1063 }
1064 for i := range rows {
1065 rows[i].Object.Object = nil
1066 }
1067 if !reflect.DeepEqual(testCase.expected, rows) {
1068 t.Errorf("mismatch: %s", cmp.Diff(testCase.expected, rows))
1069 }
1070 })
1071 }
1072 }
1073
1074 func TestPrintServiceLoadBalancer(t *testing.T) {
1075 tests := []struct {
1076 service api.Service
1077 options printers.GenerateOptions
1078 expected []metav1.TableRow
1079 }{
1080
1081 {
1082 service: api.Service{
1083 ObjectMeta: metav1.ObjectMeta{Name: "service1"},
1084 Spec: api.ServiceSpec{
1085 ClusterIPs: []string{"1.2.3.4"},
1086 Type: "LoadBalancer",
1087 Ports: []api.ServicePort{{Port: 80, Protocol: "TCP"}},
1088 },
1089 Status: api.ServiceStatus{
1090 LoadBalancer: api.LoadBalancerStatus{
1091 Ingress: []api.LoadBalancerIngress{{IP: "2.3.4.5"}, {IP: "3.4.5.6"}}},
1092 },
1093 },
1094 options: printers.GenerateOptions{},
1095
1096 expected: []metav1.TableRow{{Cells: []interface{}{"service1", "LoadBalancer", "1.2.3.4", "2.3.4.5,3.4.5.6", "80/TCP", "<unknown>"}}},
1097 },
1098
1099 {
1100 service: api.Service{
1101 ObjectMeta: metav1.ObjectMeta{Name: "service2"},
1102 Spec: api.ServiceSpec{
1103 ClusterIPs: []string{"1.3.4.5"},
1104 Type: "LoadBalancer",
1105 Ports: []api.ServicePort{{Port: 80, Protocol: "TCP"}, {Port: 8090, Protocol: "UDP"}, {Port: 8000, Protocol: "TCP"}, {Port: 7777, Protocol: "SCTP"}},
1106 },
1107 },
1108 options: printers.GenerateOptions{},
1109
1110 expected: []metav1.TableRow{{Cells: []interface{}{"service2", "LoadBalancer", "1.3.4.5", "<pending>", "80/TCP,8090/UDP,8000/TCP,7777/SCTP", "<unknown>"}}},
1111 },
1112
1113 {
1114 service: api.Service{
1115 ObjectMeta: metav1.ObjectMeta{Name: "service3"},
1116 Spec: api.ServiceSpec{
1117 ClusterIPs: []string{"1.4.5.6"},
1118 Type: "LoadBalancer",
1119 Ports: []api.ServicePort{{Port: 80, Protocol: "TCP"}, {Port: 8090, Protocol: "UDP"}, {Port: 8000, Protocol: "TCP"}},
1120 },
1121 Status: api.ServiceStatus{
1122 LoadBalancer: api.LoadBalancerStatus{
1123 Ingress: []api.LoadBalancerIngress{{IP: "2.3.4.5"}}},
1124 },
1125 },
1126 options: printers.GenerateOptions{},
1127
1128 expected: []metav1.TableRow{{Cells: []interface{}{"service3", "LoadBalancer", "1.4.5.6", "2.3.4.5", "80/TCP,8090/UDP,8000/TCP", "<unknown>"}}},
1129 },
1130
1131 {
1132 service: api.Service{
1133 ObjectMeta: metav1.ObjectMeta{Name: "service4"},
1134 Spec: api.ServiceSpec{
1135 ClusterIPs: []string{"1.5.6.7"},
1136 Type: "LoadBalancer",
1137 Ports: []api.ServicePort{{Port: 80, Protocol: "TCP"}, {Port: 8090, Protocol: "UDP"}, {Port: 8000, Protocol: "TCP"}},
1138 },
1139 Status: api.ServiceStatus{
1140 LoadBalancer: api.LoadBalancerStatus{
1141 Ingress: []api.LoadBalancerIngress{{IP: "2.3.4.5"}, {IP: "3.4.5.6"}, {IP: "5.6.7.8", Hostname: "host5678"}}},
1142 },
1143 },
1144 options: printers.GenerateOptions{},
1145
1146 expected: []metav1.TableRow{{Cells: []interface{}{"service4", "LoadBalancer", "1.5.6.7", "2.3.4.5,3.4.5...", "80/TCP,8090/UDP,8000/TCP", "<unknown>"}}},
1147 },
1148
1149 {
1150 service: api.Service{
1151 ObjectMeta: metav1.ObjectMeta{Name: "service4"},
1152 Spec: api.ServiceSpec{
1153 ClusterIPs: []string{"1.5.6.7"},
1154 Type: "LoadBalancer",
1155 Ports: []api.ServicePort{{Port: 80, Protocol: "TCP"}, {Port: 8090, Protocol: "UDP"}, {Port: 8000, Protocol: "TCP"}},
1156 Selector: map[string]string{"foo": "bar"},
1157 },
1158 Status: api.ServiceStatus{
1159 LoadBalancer: api.LoadBalancerStatus{
1160 Ingress: []api.LoadBalancerIngress{{IP: "2.3.4.5"}, {IP: "3.4.5.6"}, {IP: "5.6.7.8", Hostname: "host5678"}}},
1161 },
1162 },
1163 options: printers.GenerateOptions{Wide: true},
1164
1165 expected: []metav1.TableRow{{Cells: []interface{}{"service4", "LoadBalancer", "1.5.6.7", "2.3.4.5,3.4.5.6,5.6.7.8", "80/TCP,8090/UDP,8000/TCP", "<unknown>", "foo=bar"}}},
1166 },
1167 }
1168
1169 for i, test := range tests {
1170 rows, err := printService(&test.service, test.options)
1171 if err != nil {
1172 t.Fatalf("Error printing table rows for Service: %#v", err)
1173 }
1174 for i := range rows {
1175 rows[i].Object.Object = nil
1176 }
1177 if !reflect.DeepEqual(test.expected, rows) {
1178 t.Errorf("%d mismatch: %s", i, cmp.Diff(test.expected, rows))
1179 }
1180 }
1181 }
1182
1183 func TestPrintPod(t *testing.T) {
1184 tests := []struct {
1185 pod api.Pod
1186 expect []metav1.TableRow
1187 }{
1188 {
1189
1190 api.Pod{
1191 ObjectMeta: metav1.ObjectMeta{Name: "test1"},
1192 Spec: api.PodSpec{Containers: make([]api.Container, 2)},
1193 Status: api.PodStatus{
1194 Phase: "podPhase",
1195 ContainerStatuses: []api.ContainerStatus{
1196 {Ready: true, RestartCount: 3, State: api.ContainerState{Running: &api.ContainerStateRunning{}}},
1197 {RestartCount: 3},
1198 },
1199 },
1200 },
1201 []metav1.TableRow{{Cells: []interface{}{"test1", "1/2", "podPhase", "6", "<unknown>"}}},
1202 },
1203 {
1204
1205 api.Pod{
1206 ObjectMeta: metav1.ObjectMeta{Name: "test2"},
1207 Spec: api.PodSpec{Containers: make([]api.Container, 2)},
1208 Status: api.PodStatus{
1209 Phase: "podPhase",
1210 ContainerStatuses: []api.ContainerStatus{
1211 {Ready: true, RestartCount: 3, State: api.ContainerState{Running: &api.ContainerStateRunning{}}},
1212 {State: api.ContainerState{Waiting: &api.ContainerStateWaiting{Reason: "ContainerWaitingReason"}}, RestartCount: 3},
1213 },
1214 },
1215 },
1216 []metav1.TableRow{{Cells: []interface{}{"test2", "1/2", "ContainerWaitingReason", "6", "<unknown>"}}},
1217 },
1218 {
1219
1220 api.Pod{
1221 ObjectMeta: metav1.ObjectMeta{Name: "test3"},
1222 Spec: api.PodSpec{Containers: make([]api.Container, 2)},
1223 Status: api.PodStatus{
1224 Phase: "podPhase",
1225 ContainerStatuses: []api.ContainerStatus{
1226 {State: api.ContainerState{Waiting: &api.ContainerStateWaiting{Reason: "ContainerWaitingReason"}}, RestartCount: 3},
1227 {State: api.ContainerState{Terminated: &api.ContainerStateTerminated{Reason: "ContainerTerminatedReason"}}, RestartCount: 3},
1228 },
1229 },
1230 },
1231 []metav1.TableRow{{Cells: []interface{}{"test3", "0/2", "ContainerWaitingReason", "6", "<unknown>"}}},
1232 },
1233 {
1234
1235 api.Pod{
1236 ObjectMeta: metav1.ObjectMeta{Name: "test4"},
1237 Spec: api.PodSpec{Containers: make([]api.Container, 2)},
1238 Status: api.PodStatus{
1239 Phase: "podPhase",
1240 ContainerStatuses: []api.ContainerStatus{
1241 {Ready: true, RestartCount: 3, State: api.ContainerState{Running: &api.ContainerStateRunning{}}},
1242 {Ready: true, RestartCount: 3},
1243 },
1244 },
1245 },
1246 []metav1.TableRow{{Cells: []interface{}{"test4", "1/2", "podPhase", "6", "<unknown>"}}},
1247 },
1248 {
1249
1250 api.Pod{
1251 ObjectMeta: metav1.ObjectMeta{Name: "test5"},
1252 Spec: api.PodSpec{Containers: make([]api.Container, 2)},
1253 Status: api.PodStatus{
1254 Reason: "podReason",
1255 Phase: "podPhase",
1256 ContainerStatuses: []api.ContainerStatus{
1257 {Ready: true, RestartCount: 3, State: api.ContainerState{Running: &api.ContainerStateRunning{}}},
1258 {Ready: true, RestartCount: 3},
1259 },
1260 },
1261 },
1262 []metav1.TableRow{{Cells: []interface{}{"test5", "1/2", "podReason", "6", "<unknown>"}}},
1263 },
1264 {
1265
1266 api.Pod{
1267 ObjectMeta: metav1.ObjectMeta{Name: "test6"},
1268 Spec: api.PodSpec{Containers: make([]api.Container, 2)},
1269 Status: api.PodStatus{
1270 Phase: "Running",
1271 Reason: "",
1272 ContainerStatuses: []api.ContainerStatus{
1273 {Ready: true, RestartCount: 3, State: api.ContainerState{Terminated: &api.ContainerStateTerminated{Reason: "Completed", ExitCode: 0}}},
1274 {Ready: true, RestartCount: 3, State: api.ContainerState{Running: &api.ContainerStateRunning{}}},
1275 },
1276 },
1277 },
1278 []metav1.TableRow{{Cells: []interface{}{"test6", "1/2", "NotReady", "6", "<unknown>"}}},
1279 },
1280 {
1281
1282 api.Pod{
1283 ObjectMeta: metav1.ObjectMeta{Name: "test6"},
1284 Spec: api.PodSpec{Containers: make([]api.Container, 2)},
1285 Status: api.PodStatus{
1286 Phase: "Running",
1287 Reason: "",
1288 ContainerStatuses: []api.ContainerStatus{
1289 {Ready: true, RestartCount: 3, State: api.ContainerState{Terminated: &api.ContainerStateTerminated{Reason: "Completed", ExitCode: 0}}},
1290 {Ready: true, RestartCount: 3, State: api.ContainerState{Running: &api.ContainerStateRunning{}}},
1291 },
1292 Conditions: []api.PodCondition{
1293 {Type: api.PodReady, Status: api.ConditionTrue, LastProbeTime: metav1.Time{Time: time.Now()}},
1294 },
1295 },
1296 },
1297 []metav1.TableRow{{Cells: []interface{}{"test6", "1/2", "Running", "6", "<unknown>"}}},
1298 },
1299 {
1300
1301 api.Pod{
1302 ObjectMeta: metav1.ObjectMeta{Name: "test7"},
1303 Spec: api.PodSpec{InitContainers: make([]api.Container, 1), Containers: make([]api.Container, 1)},
1304 Status: api.PodStatus{
1305 Phase: "podPhase",
1306 InitContainerStatuses: []api.ContainerStatus{
1307 {
1308 Ready: false,
1309 RestartCount: 3,
1310 State: api.ContainerState{Running: &api.ContainerStateRunning{}},
1311 LastTerminationState: api.ContainerState{Terminated: &api.ContainerStateTerminated{FinishedAt: metav1.NewTime(time.Now().Add(-10 * time.Second))}},
1312 },
1313 },
1314 ContainerStatuses: []api.ContainerStatus{
1315 {
1316 Ready: false,
1317 RestartCount: 0,
1318 State: api.ContainerState{Waiting: &api.ContainerStateWaiting{}},
1319 },
1320 },
1321 },
1322 },
1323 []metav1.TableRow{{Cells: []interface{}{"test7", "0/1", "Init:0/1", "3 (10s ago)", "<unknown>"}}},
1324 },
1325 {
1326
1327 api.Pod{
1328 ObjectMeta: metav1.ObjectMeta{Name: "test8"},
1329 Spec: api.PodSpec{InitContainers: make([]api.Container, 2), Containers: make([]api.Container, 1)},
1330 Status: api.PodStatus{
1331 Phase: "podPhase",
1332 InitContainerStatuses: []api.ContainerStatus{
1333 {
1334 Ready: false,
1335 RestartCount: 3,
1336 State: api.ContainerState{Running: &api.ContainerStateRunning{}},
1337 LastTerminationState: api.ContainerState{Terminated: &api.ContainerStateTerminated{FinishedAt: metav1.NewTime(time.Now().Add(-10 * time.Second))}},
1338 },
1339 {
1340 Ready: false,
1341 State: api.ContainerState{Waiting: &api.ContainerStateWaiting{}},
1342 },
1343 },
1344 ContainerStatuses: []api.ContainerStatus{
1345 {
1346 Ready: false,
1347 State: api.ContainerState{Waiting: &api.ContainerStateWaiting{}},
1348 },
1349 },
1350 },
1351 },
1352 []metav1.TableRow{{Cells: []interface{}{"test8", "0/1", "Init:0/2", "3 (10s ago)", "<unknown>"}}},
1353 },
1354 {
1355
1356 api.Pod{
1357 ObjectMeta: metav1.ObjectMeta{Name: "test9"},
1358 Spec: api.PodSpec{InitContainers: make([]api.Container, 2), Containers: make([]api.Container, 1)},
1359 Status: api.PodStatus{
1360 Phase: "podPhase",
1361 InitContainerStatuses: []api.ContainerStatus{
1362 {
1363 Ready: false,
1364 State: api.ContainerState{Terminated: &api.ContainerStateTerminated{}},
1365 },
1366 {
1367 Ready: false,
1368 RestartCount: 3,
1369 State: api.ContainerState{Running: &api.ContainerStateRunning{}},
1370 LastTerminationState: api.ContainerState{Terminated: &api.ContainerStateTerminated{FinishedAt: metav1.NewTime(time.Now().Add(-10 * time.Second))}},
1371 },
1372 },
1373 ContainerStatuses: []api.ContainerStatus{
1374 {
1375 Ready: false,
1376 State: api.ContainerState{Waiting: &api.ContainerStateWaiting{}},
1377 },
1378 },
1379 },
1380 },
1381 []metav1.TableRow{{Cells: []interface{}{"test9", "0/1", "Init:1/2", "3 (10s ago)", "<unknown>"}}},
1382 },
1383 {
1384
1385 api.Pod{
1386 ObjectMeta: metav1.ObjectMeta{Name: "test10"},
1387 Spec: api.PodSpec{InitContainers: make([]api.Container, 2), Containers: make([]api.Container, 1)},
1388 Status: api.PodStatus{
1389 Phase: "podPhase",
1390 InitContainerStatuses: []api.ContainerStatus{
1391 {
1392 Ready: false,
1393 RestartCount: 2,
1394 State: api.ContainerState{Terminated: &api.ContainerStateTerminated{}},
1395 LastTerminationState: api.ContainerState{Terminated: &api.ContainerStateTerminated{FinishedAt: metav1.NewTime(time.Now().Add(-2 * time.Minute))}},
1396 },
1397 {
1398 Ready: false,
1399 RestartCount: 3,
1400 State: api.ContainerState{Running: &api.ContainerStateRunning{}},
1401 LastTerminationState: api.ContainerState{Terminated: &api.ContainerStateTerminated{FinishedAt: metav1.NewTime(time.Now().Add(-10 * time.Second))}},
1402 },
1403 },
1404 ContainerStatuses: []api.ContainerStatus{
1405 {
1406 Ready: false,
1407 State: api.ContainerState{Waiting: &api.ContainerStateWaiting{}},
1408 },
1409 },
1410 },
1411 },
1412 []metav1.TableRow{{Cells: []interface{}{"test10", "0/1", "Init:1/2", "5 (10s ago)", "<unknown>"}}},
1413 },
1414 {
1415
1416 api.Pod{
1417 ObjectMeta: metav1.ObjectMeta{Name: "test11"},
1418 Spec: api.PodSpec{InitContainers: make([]api.Container, 1), Containers: make([]api.Container, 1)},
1419 Status: api.PodStatus{
1420 Phase: "Running",
1421 InitContainerStatuses: []api.ContainerStatus{
1422 {
1423 Ready: false,
1424 RestartCount: 2,
1425 State: api.ContainerState{Terminated: &api.ContainerStateTerminated{}},
1426 LastTerminationState: api.ContainerState{Terminated: &api.ContainerStateTerminated{FinishedAt: metav1.NewTime(time.Now().Add(-2 * time.Minute))}},
1427 },
1428 },
1429 ContainerStatuses: []api.ContainerStatus{
1430 {
1431 Ready: false,
1432 RestartCount: 4,
1433 State: api.ContainerState{Running: &api.ContainerStateRunning{}},
1434 LastTerminationState: api.ContainerState{Terminated: &api.ContainerStateTerminated{FinishedAt: metav1.NewTime(time.Now().Add(-20 * time.Second))}},
1435 },
1436 },
1437 },
1438 },
1439 []metav1.TableRow{{Cells: []interface{}{"test11", "0/1", "Running", "4 (20s ago)", "<unknown>"}}},
1440 },
1441 {
1442
1443 api.Pod{
1444 ObjectMeta: metav1.ObjectMeta{Name: "test12"},
1445 Spec: api.PodSpec{Containers: make([]api.Container, 1)},
1446 Status: api.PodStatus{
1447 Phase: "Running",
1448 ContainerStatuses: []api.ContainerStatus{
1449 {
1450 Ready: true,
1451 RestartCount: 3,
1452 State: api.ContainerState{Running: &api.ContainerStateRunning{}},
1453 LastTerminationState: api.ContainerState{Terminated: &api.ContainerStateTerminated{FinishedAt: metav1.NewTime(time.Now().Add(-5 * 24 * time.Hour))}},
1454 },
1455 },
1456 },
1457 },
1458 []metav1.TableRow{{Cells: []interface{}{"test12", "1/1", "Running", "3 (5d ago)", "<unknown>"}}},
1459 },
1460 {
1461
1462 api.Pod{
1463 ObjectMeta: metav1.ObjectMeta{Name: "test13"},
1464 Spec: api.PodSpec{Containers: make([]api.Container, 2)},
1465 Status: api.PodStatus{
1466 Phase: "Running",
1467 ContainerStatuses: []api.ContainerStatus{
1468 {
1469 Ready: true,
1470 RestartCount: 0,
1471 State: api.ContainerState{Running: &api.ContainerStateRunning{}},
1472 },
1473 {
1474 Ready: true,
1475 RestartCount: 3,
1476 State: api.ContainerState{Running: &api.ContainerStateRunning{}},
1477 LastTerminationState: api.ContainerState{Terminated: &api.ContainerStateTerminated{FinishedAt: metav1.NewTime(time.Now().Add(-10 * 24 * time.Hour))}},
1478 },
1479 },
1480 },
1481 },
1482 []metav1.TableRow{{Cells: []interface{}{"test13", "2/2", "Running", "3 (10d ago)", "<unknown>"}}},
1483 },
1484 {
1485
1486 api.Pod{
1487 ObjectMeta: metav1.ObjectMeta{Name: "test14"},
1488 Spec: api.PodSpec{Containers: make([]api.Container, 2)},
1489 Status: api.PodStatus{
1490 Phase: "Running",
1491 ContainerStatuses: []api.ContainerStatus{
1492 {
1493 Ready: true,
1494 RestartCount: 6,
1495 State: api.ContainerState{Running: &api.ContainerStateRunning{}},
1496 LastTerminationState: api.ContainerState{Terminated: &api.ContainerStateTerminated{FinishedAt: metav1.NewTime(time.Now().Add(-5 * 24 * time.Hour))}},
1497 },
1498 {
1499 Ready: true,
1500 RestartCount: 3,
1501 State: api.ContainerState{Running: &api.ContainerStateRunning{}},
1502 LastTerminationState: api.ContainerState{Terminated: &api.ContainerStateTerminated{FinishedAt: metav1.NewTime(time.Now().Add(-20 * 24 * time.Hour))}},
1503 },
1504 },
1505 },
1506 },
1507 []metav1.TableRow{{Cells: []interface{}{"test14", "2/2", "Running", "9 (5d ago)", "<unknown>"}}},
1508 },
1509 {
1510
1511 api.Pod{
1512 ObjectMeta: metav1.ObjectMeta{Name: "test15"},
1513 Spec: api.PodSpec{Containers: make([]api.Container, 2)},
1514 Status: api.PodStatus{
1515 Phase: "podPhase",
1516 Conditions: []api.PodCondition{
1517 {
1518 Type: api.PodScheduled,
1519 Status: api.ConditionFalse,
1520 Reason: apiv1.PodReasonSchedulingGated,
1521 },
1522 },
1523 },
1524 },
1525 []metav1.TableRow{{Cells: []interface{}{"test15", "0/2", apiv1.PodReasonSchedulingGated, "0", "<unknown>"}}},
1526 },
1527 }
1528
1529 for i, test := range tests {
1530 rows, err := printPod(&test.pod, printers.GenerateOptions{})
1531 if err != nil {
1532 t.Fatal(err)
1533 }
1534 for i := range rows {
1535 rows[i].Object.Object = nil
1536 }
1537 if !reflect.DeepEqual(test.expect, rows) {
1538 t.Errorf("%d mismatch: %s", i, cmp.Diff(test.expect, rows))
1539 }
1540 }
1541 }
1542
1543 func TestPrintPodWithRestartableInitContainer(t *testing.T) {
1544 tests := []struct {
1545 pod api.Pod
1546 expect []metav1.TableRow
1547 }{
1548 {
1549
1550 api.Pod{
1551 ObjectMeta: metav1.ObjectMeta{Name: "test1"},
1552 Spec: api.PodSpec{
1553 InitContainers: []api.Container{
1554 {Name: "restartable-init-1", RestartPolicy: &containerRestartPolicyAlways},
1555 {Name: "restartable-init-2", RestartPolicy: &containerRestartPolicyAlways},
1556 }, Containers: make([]api.Container, 1)},
1557 Status: api.PodStatus{
1558 Phase: "Pending",
1559 InitContainerStatuses: []api.ContainerStatus{
1560 {
1561 Name: "restartable-init-1",
1562 Ready: false,
1563 RestartCount: 3,
1564 State: api.ContainerState{Running: &api.ContainerStateRunning{}},
1565 Started: utilpointer.Bool(false),
1566 LastTerminationState: api.ContainerState{Terminated: &api.ContainerStateTerminated{FinishedAt: metav1.NewTime(time.Now().Add(-10 * time.Second))}},
1567 },
1568 {
1569 Name: "restartable-init-2",
1570 Ready: false,
1571 State: api.ContainerState{Waiting: &api.ContainerStateWaiting{}},
1572 Started: utilpointer.Bool(false),
1573 },
1574 },
1575 ContainerStatuses: []api.ContainerStatus{
1576 {
1577 Ready: false,
1578 RestartCount: 0,
1579 State: api.ContainerState{Waiting: &api.ContainerStateWaiting{}},
1580 },
1581 },
1582 Conditions: []api.PodCondition{
1583 {Type: api.PodInitialized, Status: api.ConditionFalse},
1584 },
1585 },
1586 },
1587 []metav1.TableRow{{Cells: []interface{}{"test1", "0/3", "Init:0/2", "3 (10s ago)", "<unknown>"}}},
1588 },
1589 {
1590
1591 api.Pod{
1592 ObjectMeta: metav1.ObjectMeta{Name: "test1"},
1593 Spec: api.PodSpec{
1594 InitContainers: []api.Container{
1595 {Name: "restartable-init-1", RestartPolicy: &containerRestartPolicyAlways},
1596 {Name: "restartable-init-2", RestartPolicy: &containerRestartPolicyAlways},
1597 }, Containers: make([]api.Container, 1)},
1598 Status: api.PodStatus{
1599 Phase: "Pending",
1600 InitContainerStatuses: []api.ContainerStatus{
1601 {
1602 Name: "restartable-init-1",
1603 Ready: false,
1604 RestartCount: 3,
1605 State: api.ContainerState{Running: &api.ContainerStateRunning{}},
1606 Started: utilpointer.Bool(true),
1607 LastTerminationState: api.ContainerState{Terminated: &api.ContainerStateTerminated{FinishedAt: metav1.NewTime(time.Now().Add(-10 * time.Second))}},
1608 },
1609 {
1610 Name: "restartable-init-2",
1611 Ready: false,
1612 State: api.ContainerState{Running: &api.ContainerStateRunning{}},
1613 Started: utilpointer.Bool(false),
1614 },
1615 },
1616 ContainerStatuses: []api.ContainerStatus{
1617 {
1618 Ready: false,
1619 RestartCount: 0,
1620 State: api.ContainerState{Waiting: &api.ContainerStateWaiting{}},
1621 },
1622 },
1623 Conditions: []api.PodCondition{
1624 {Type: api.PodInitialized, Status: api.ConditionFalse},
1625 },
1626 },
1627 },
1628 []metav1.TableRow{{Cells: []interface{}{"test1", "0/3", "Init:1/2", "3 (10s ago)", "<unknown>"}}},
1629 },
1630 {
1631
1632 api.Pod{
1633 ObjectMeta: metav1.ObjectMeta{Name: "test2"},
1634 Spec: api.PodSpec{
1635 InitContainers: []api.Container{
1636 {Name: "restartable-init-1", RestartPolicy: &containerRestartPolicyAlways},
1637 {Name: "restartable-init-2", RestartPolicy: &containerRestartPolicyAlways},
1638 }, Containers: make([]api.Container, 1)},
1639 Status: api.PodStatus{
1640 Phase: "Running",
1641 InitContainerStatuses: []api.ContainerStatus{
1642 {
1643 Name: "restartable-init-1",
1644 Ready: false,
1645 RestartCount: 3,
1646 State: api.ContainerState{Running: &api.ContainerStateRunning{}},
1647 Started: utilpointer.Bool(true),
1648 LastTerminationState: api.ContainerState{Terminated: &api.ContainerStateTerminated{FinishedAt: metav1.NewTime(time.Now().Add(-10 * time.Second))}},
1649 },
1650 {
1651 Name: "restartable-init-2",
1652 Ready: false,
1653 State: api.ContainerState{Running: &api.ContainerStateRunning{}},
1654 Started: utilpointer.Bool(true),
1655 },
1656 },
1657 ContainerStatuses: []api.ContainerStatus{
1658 {
1659 Ready: true,
1660 RestartCount: 4,
1661 State: api.ContainerState{Running: &api.ContainerStateRunning{}},
1662 LastTerminationState: api.ContainerState{Terminated: &api.ContainerStateTerminated{FinishedAt: metav1.NewTime(time.Now().Add(-20 * time.Second))}},
1663 },
1664 },
1665 Conditions: []api.PodCondition{
1666 {Type: api.PodInitialized, Status: api.ConditionTrue},
1667 },
1668 },
1669 },
1670 []metav1.TableRow{{Cells: []interface{}{"test2", "1/3", "Running", "7 (10s ago)", "<unknown>"}}},
1671 },
1672 {
1673
1674 api.Pod{
1675 ObjectMeta: metav1.ObjectMeta{Name: "test3"},
1676 Spec: api.PodSpec{
1677 InitContainers: []api.Container{
1678 {Name: "restartable-init-1", RestartPolicy: &containerRestartPolicyAlways},
1679 {Name: "restartable-init-2", RestartPolicy: &containerRestartPolicyAlways},
1680 }, Containers: make([]api.Container, 1)},
1681 Status: api.PodStatus{
1682 Phase: "Succeeded",
1683 InitContainerStatuses: []api.ContainerStatus{
1684 {
1685 Name: "restartable-init-1",
1686 Ready: false,
1687 RestartCount: 3,
1688 State: api.ContainerState{Terminated: &api.ContainerStateTerminated{Reason: "Error", ExitCode: 137}},
1689 Started: utilpointer.Bool(false),
1690 LastTerminationState: api.ContainerState{Terminated: &api.ContainerStateTerminated{FinishedAt: metav1.NewTime(time.Now().Add(-10 * time.Second))}},
1691 },
1692 {
1693 Name: "restartable-init-2",
1694 Ready: false,
1695 State: api.ContainerState{Terminated: &api.ContainerStateTerminated{Reason: "Error", ExitCode: 137}},
1696 Started: utilpointer.Bool(false),
1697 },
1698 },
1699 ContainerStatuses: []api.ContainerStatus{
1700 {
1701 Ready: false,
1702 RestartCount: 4,
1703 State: api.ContainerState{Terminated: &api.ContainerStateTerminated{Reason: "Completed", ExitCode: 0}},
1704 LastTerminationState: api.ContainerState{Terminated: &api.ContainerStateTerminated{FinishedAt: metav1.NewTime(time.Now().Add(-20 * time.Second))}},
1705 },
1706 },
1707 Conditions: []api.PodCondition{
1708 {Type: api.PodInitialized, Status: api.ConditionTrue},
1709 },
1710 },
1711 },
1712 []metav1.TableRow{
1713 {
1714 Cells: []interface{}{"test3", "0/3", "Completed", "7 (10s ago)", "<unknown>"},
1715 Conditions: []metav1.TableRowCondition{
1716 {Type: metav1.RowCompleted, Status: metav1.ConditionTrue, Reason: "Succeeded", Message: "The pod has completed successfully."},
1717 },
1718 },
1719 },
1720 },
1721 }
1722
1723 for i, test := range tests {
1724 rows, err := printPod(&test.pod, printers.GenerateOptions{})
1725 if err != nil {
1726 t.Fatal(err)
1727 }
1728 for i := range rows {
1729 rows[i].Object.Object = nil
1730 }
1731 if !reflect.DeepEqual(test.expect, rows) {
1732 t.Errorf("%d mismatch: %s", i, cmp.Diff(test.expect, rows))
1733 }
1734 }
1735 }
1736
1737 func TestPrintPodwide(t *testing.T) {
1738 condition1 := "condition1"
1739 condition2 := "condition2"
1740 condition3 := "condition3"
1741 tests := []struct {
1742 pod api.Pod
1743 expect []metav1.TableRow
1744 }{
1745 {
1746
1747 api.Pod{
1748 ObjectMeta: metav1.ObjectMeta{Name: "test1"},
1749 Spec: api.PodSpec{
1750 Containers: make([]api.Container, 2),
1751 NodeName: "test1",
1752 ReadinessGates: []api.PodReadinessGate{
1753 {
1754 ConditionType: api.PodConditionType(condition1),
1755 },
1756 {
1757 ConditionType: api.PodConditionType(condition2),
1758 },
1759 {
1760 ConditionType: api.PodConditionType(condition3),
1761 },
1762 },
1763 },
1764 Status: api.PodStatus{
1765 Conditions: []api.PodCondition{
1766 {
1767 Type: api.PodConditionType(condition1),
1768 Status: api.ConditionFalse,
1769 },
1770 {
1771 Type: api.PodConditionType(condition2),
1772 Status: api.ConditionTrue,
1773 },
1774 },
1775 Phase: "podPhase",
1776 PodIPs: []api.PodIP{{IP: "1.1.1.1"}},
1777 ContainerStatuses: []api.ContainerStatus{
1778 {Ready: true, RestartCount: 3, State: api.ContainerState{Running: &api.ContainerStateRunning{}}},
1779 {RestartCount: 3},
1780 },
1781 NominatedNodeName: "node1",
1782 },
1783 },
1784 []metav1.TableRow{{Cells: []interface{}{"test1", "1/2", "podPhase", "6", "<unknown>", "1.1.1.1", "test1", "node1", "1/3"}}},
1785 },
1786 {
1787
1788 api.Pod{
1789 ObjectMeta: metav1.ObjectMeta{Name: "test1"},
1790 Spec: api.PodSpec{
1791 Containers: make([]api.Container, 2),
1792 NodeName: "test1",
1793 ReadinessGates: []api.PodReadinessGate{
1794 {
1795 ConditionType: api.PodConditionType(condition1),
1796 },
1797 {
1798 ConditionType: api.PodConditionType(condition2),
1799 },
1800 {
1801 ConditionType: api.PodConditionType(condition3),
1802 },
1803 },
1804 },
1805 Status: api.PodStatus{
1806 Conditions: []api.PodCondition{
1807 {
1808 Type: api.PodConditionType(condition1),
1809 Status: api.ConditionFalse,
1810 },
1811 {
1812 Type: api.PodConditionType(condition2),
1813 Status: api.ConditionTrue,
1814 },
1815 },
1816 Phase: "podPhase",
1817 PodIPs: []api.PodIP{{IP: "1.1.1.1"}, {IP: "2001:db8::"}},
1818 ContainerStatuses: []api.ContainerStatus{
1819 {Ready: true, RestartCount: 3, State: api.ContainerState{Running: &api.ContainerStateRunning{}}},
1820 {RestartCount: 3},
1821 },
1822 NominatedNodeName: "node1",
1823 },
1824 },
1825 []metav1.TableRow{{Cells: []interface{}{"test1", "1/2", "podPhase", "6", "<unknown>", "1.1.1.1", "test1", "node1", "1/3"}}},
1826 },
1827 {
1828
1829 api.Pod{
1830 ObjectMeta: metav1.ObjectMeta{Name: "test2"},
1831 Spec: api.PodSpec{
1832 Containers: make([]api.Container, 2),
1833 NodeName: "",
1834 },
1835 Status: api.PodStatus{
1836 Phase: "podPhase",
1837 ContainerStatuses: []api.ContainerStatus{
1838 {Ready: true, RestartCount: 3, State: api.ContainerState{Running: &api.ContainerStateRunning{}}},
1839 {State: api.ContainerState{Waiting: &api.ContainerStateWaiting{Reason: "ContainerWaitingReason"}}, RestartCount: 3},
1840 },
1841 },
1842 },
1843 []metav1.TableRow{{Cells: []interface{}{"test2", "1/2", "ContainerWaitingReason", "6", "<unknown>", "<none>", "<none>", "<none>", "<none>"}}},
1844 },
1845 }
1846
1847 for i, test := range tests {
1848 rows, err := printPod(&test.pod, printers.GenerateOptions{Wide: true})
1849 if err != nil {
1850 t.Fatal(err)
1851 }
1852 for i := range rows {
1853 rows[i].Object.Object = nil
1854 }
1855 if !reflect.DeepEqual(test.expect, rows) {
1856 t.Errorf("%d mismatch: %s", i, cmp.Diff(test.expect, rows))
1857 }
1858 }
1859 }
1860
1861 func TestPrintPodConditions(t *testing.T) {
1862 runningPod := &api.Pod{
1863 ObjectMeta: metav1.ObjectMeta{Name: "test1", Labels: map[string]string{"a": "1", "b": "2"}},
1864 Spec: api.PodSpec{Containers: make([]api.Container, 2)},
1865 Status: api.PodStatus{
1866 Phase: "Running",
1867 ContainerStatuses: []api.ContainerStatus{
1868 {Ready: true, RestartCount: 3, State: api.ContainerState{Running: &api.ContainerStateRunning{}}},
1869 {RestartCount: 3},
1870 },
1871 },
1872 }
1873 succeededPod := &api.Pod{
1874 ObjectMeta: metav1.ObjectMeta{Name: "test1", Labels: map[string]string{"a": "1", "b": "2"}},
1875 Spec: api.PodSpec{Containers: make([]api.Container, 2)},
1876 Status: api.PodStatus{
1877 Phase: "Succeeded",
1878 ContainerStatuses: []api.ContainerStatus{
1879 {Ready: true, RestartCount: 3, State: api.ContainerState{Running: &api.ContainerStateRunning{}}},
1880 {RestartCount: 3},
1881 },
1882 },
1883 }
1884 failedPod := &api.Pod{
1885 ObjectMeta: metav1.ObjectMeta{Name: "test2", Labels: map[string]string{"b": "2"}},
1886 Spec: api.PodSpec{Containers: make([]api.Container, 2)},
1887 Status: api.PodStatus{
1888 Phase: "Failed",
1889 ContainerStatuses: []api.ContainerStatus{
1890 {Ready: true, RestartCount: 3, State: api.ContainerState{Running: &api.ContainerStateRunning{}}},
1891 {RestartCount: 3},
1892 },
1893 },
1894 }
1895 tests := []struct {
1896 pod *api.Pod
1897 expect []metav1.TableRow
1898 }{
1899
1900 {
1901 pod: runningPod,
1902
1903 expect: []metav1.TableRow{{Cells: []interface{}{"test1", "1/2", "Running", "6", "<unknown>"}}},
1904 },
1905
1906 {
1907 pod: succeededPod,
1908 expect: []metav1.TableRow{
1909 {
1910
1911 Cells: []interface{}{"test1", "1/2", "Succeeded", "6", "<unknown>"},
1912 Conditions: podSuccessConditions,
1913 },
1914 },
1915 },
1916
1917 {
1918 pod: failedPod,
1919 expect: []metav1.TableRow{
1920 {
1921
1922 Cells: []interface{}{"test2", "1/2", "Failed", "6", "<unknown>"},
1923 Conditions: podFailedConditions,
1924 },
1925 },
1926 },
1927 }
1928
1929 for i, test := range tests {
1930 rows, err := printPod(test.pod, printers.GenerateOptions{})
1931 if err != nil {
1932 t.Fatal(err)
1933 }
1934 for i := range rows {
1935 rows[i].Object.Object = nil
1936 }
1937 if !reflect.DeepEqual(test.expect, rows) {
1938 t.Errorf("%d mismatch: %s", i, cmp.Diff(test.expect, rows))
1939 }
1940 }
1941 }
1942
1943 func TestPrintPodList(t *testing.T) {
1944 tests := []struct {
1945 pods api.PodList
1946 expect []metav1.TableRow
1947 }{
1948
1949 {
1950 api.PodList{
1951 Items: []api.Pod{
1952 {
1953 ObjectMeta: metav1.ObjectMeta{Name: "test1"},
1954 Spec: api.PodSpec{Containers: make([]api.Container, 2)},
1955 Status: api.PodStatus{
1956 Phase: "podPhase",
1957 ContainerStatuses: []api.ContainerStatus{
1958 {Ready: true, RestartCount: 3, State: api.ContainerState{Running: &api.ContainerStateRunning{}}},
1959 {Ready: true, RestartCount: 3, State: api.ContainerState{Running: &api.ContainerStateRunning{}}},
1960 },
1961 },
1962 },
1963 {
1964 ObjectMeta: metav1.ObjectMeta{Name: "test2"},
1965 Spec: api.PodSpec{Containers: make([]api.Container, 1)},
1966 Status: api.PodStatus{
1967 Phase: "podPhase",
1968 ContainerStatuses: []api.ContainerStatus{
1969 {Ready: true, RestartCount: 1, State: api.ContainerState{Running: &api.ContainerStateRunning{}}},
1970 },
1971 },
1972 },
1973 },
1974 },
1975 []metav1.TableRow{{Cells: []interface{}{"test1", "2/2", "podPhase", "6", "<unknown>"}}, {Cells: []interface{}{"test2", "1/1", "podPhase", "1", "<unknown>"}}},
1976 },
1977 }
1978
1979 for _, test := range tests {
1980 rows, err := printPodList(&test.pods, printers.GenerateOptions{})
1981
1982 if err != nil {
1983 t.Fatal(err)
1984 }
1985 for i := range rows {
1986 rows[i].Object.Object = nil
1987 }
1988 if !reflect.DeepEqual(test.expect, rows) {
1989 t.Errorf("mismatch: %s", cmp.Diff(test.expect, rows))
1990 }
1991 }
1992 }
1993
1994 func TestPrintNonTerminatedPod(t *testing.T) {
1995 tests := []struct {
1996 pod api.Pod
1997 expect []metav1.TableRow
1998 }{
1999 {
2000
2001 api.Pod{
2002 ObjectMeta: metav1.ObjectMeta{Name: "test1"},
2003 Spec: api.PodSpec{Containers: make([]api.Container, 2)},
2004 Status: api.PodStatus{
2005 Phase: api.PodRunning,
2006 ContainerStatuses: []api.ContainerStatus{
2007 {Ready: true, RestartCount: 3, State: api.ContainerState{Running: &api.ContainerStateRunning{}}},
2008 {RestartCount: 3},
2009 },
2010 },
2011 },
2012
2013 []metav1.TableRow{{Cells: []interface{}{"test1", "1/2", "Running", "6", "<unknown>"}}},
2014 },
2015 {
2016
2017 api.Pod{
2018 ObjectMeta: metav1.ObjectMeta{Name: "test2"},
2019 Spec: api.PodSpec{Containers: make([]api.Container, 2)},
2020 Status: api.PodStatus{
2021 Phase: api.PodPending,
2022 ContainerStatuses: []api.ContainerStatus{
2023 {Ready: true, RestartCount: 3, State: api.ContainerState{Running: &api.ContainerStateRunning{}}},
2024 {RestartCount: 3},
2025 },
2026 },
2027 },
2028
2029 []metav1.TableRow{{Cells: []interface{}{"test2", "1/2", "Pending", "6", "<unknown>"}}},
2030 },
2031 {
2032
2033 api.Pod{
2034 ObjectMeta: metav1.ObjectMeta{Name: "test3"},
2035 Spec: api.PodSpec{Containers: make([]api.Container, 2)},
2036 Status: api.PodStatus{
2037 Phase: api.PodUnknown,
2038 ContainerStatuses: []api.ContainerStatus{
2039 {Ready: true, RestartCount: 3, State: api.ContainerState{Running: &api.ContainerStateRunning{}}},
2040 {RestartCount: 3},
2041 },
2042 },
2043 },
2044
2045 []metav1.TableRow{{Cells: []interface{}{"test3", "1/2", "Unknown", "6", "<unknown>"}}},
2046 },
2047 {
2048
2049 api.Pod{
2050 ObjectMeta: metav1.ObjectMeta{Name: "test4"},
2051 Spec: api.PodSpec{Containers: make([]api.Container, 2)},
2052 Status: api.PodStatus{
2053 Phase: api.PodSucceeded,
2054 ContainerStatuses: []api.ContainerStatus{
2055 {Ready: true, RestartCount: 3, State: api.ContainerState{Running: &api.ContainerStateRunning{}}},
2056 {RestartCount: 3},
2057 },
2058 },
2059 },
2060
2061 []metav1.TableRow{
2062 {
2063 Cells: []interface{}{"test4", "1/2", "Succeeded", "6", "<unknown>"},
2064 Conditions: podSuccessConditions,
2065 },
2066 },
2067 },
2068 {
2069
2070 api.Pod{
2071 ObjectMeta: metav1.ObjectMeta{Name: "test5"},
2072 Spec: api.PodSpec{Containers: make([]api.Container, 2)},
2073 Status: api.PodStatus{
2074 Phase: api.PodFailed,
2075 ContainerStatuses: []api.ContainerStatus{
2076 {Ready: true, RestartCount: 3, State: api.ContainerState{Running: &api.ContainerStateRunning{}}},
2077 {Ready: true, RestartCount: 3},
2078 },
2079 },
2080 },
2081
2082 []metav1.TableRow{
2083 {
2084 Cells: []interface{}{"test5", "1/2", "Failed", "6", "<unknown>"},
2085 Conditions: podFailedConditions,
2086 },
2087 },
2088 },
2089 }
2090
2091 for i, test := range tests {
2092 rows, err := printPod(&test.pod, printers.GenerateOptions{})
2093 if err != nil {
2094 t.Fatal(err)
2095 }
2096 for i := range rows {
2097 rows[i].Object.Object = nil
2098 }
2099 if !reflect.DeepEqual(test.expect, rows) {
2100 t.Errorf("%d mismatch: %s", i, cmp.Diff(test.expect, rows))
2101 }
2102 }
2103 }
2104
2105 func TestPrintPodTemplate(t *testing.T) {
2106 tests := []struct {
2107 podTemplate api.PodTemplate
2108 options printers.GenerateOptions
2109 expected []metav1.TableRow
2110 }{
2111
2112 {
2113 podTemplate: api.PodTemplate{
2114 ObjectMeta: metav1.ObjectMeta{Name: "pod-template-1"},
2115 Template: api.PodTemplateSpec{
2116 ObjectMeta: metav1.ObjectMeta{Name: "pod-template-1"},
2117 Spec: api.PodSpec{
2118 Containers: []api.Container{},
2119 },
2120 },
2121 },
2122
2123 options: printers.GenerateOptions{},
2124
2125 expected: []metav1.TableRow{{Cells: []interface{}{"pod-template-1", "", "", "<none>"}}},
2126 },
2127
2128 {
2129 podTemplate: api.PodTemplate{
2130 ObjectMeta: metav1.ObjectMeta{Name: "pod-template-2"},
2131 Template: api.PodTemplateSpec{
2132 ObjectMeta: metav1.ObjectMeta{Name: "pod-template-2"},
2133 Spec: api.PodSpec{
2134 Containers: []api.Container{
2135 {
2136 Name: "fake-container1",
2137 Image: "fake-image1",
2138 },
2139 {
2140 Name: "fake-container2",
2141 Image: "fake-image2",
2142 },
2143 },
2144 },
2145 },
2146 },
2147
2148 options: printers.GenerateOptions{},
2149
2150 expected: []metav1.TableRow{{Cells: []interface{}{"pod-template-2", "fake-container1,fake-container2", "fake-image1,fake-image2", "<none>"}}},
2151 },
2152
2153 {
2154 podTemplate: api.PodTemplate{
2155 ObjectMeta: metav1.ObjectMeta{Name: "pod-template-3"},
2156 Template: api.PodTemplateSpec{
2157 ObjectMeta: metav1.ObjectMeta{
2158 Name: "pod-template-3",
2159 Labels: map[string]string{"foo": "bar"},
2160 },
2161 Spec: api.PodSpec{
2162 Containers: []api.Container{},
2163 },
2164 },
2165 },
2166
2167 options: printers.GenerateOptions{},
2168
2169 expected: []metav1.TableRow{{Cells: []interface{}{"pod-template-3", "", "", "foo=bar"}}},
2170 },
2171 }
2172
2173 for i, test := range tests {
2174 rows, err := printPodTemplate(&test.podTemplate, test.options)
2175 if err != nil {
2176 t.Fatal(err)
2177 }
2178 for i := range rows {
2179 rows[i].Object.Object = nil
2180 }
2181 if !reflect.DeepEqual(test.expected, rows) {
2182 t.Errorf("%d mismatch: %s", i, cmp.Diff(test.expected, rows))
2183 }
2184 }
2185 }
2186
2187 func TestPrintPodTemplateList(t *testing.T) {
2188
2189 templateList := api.PodTemplateList{
2190 Items: []api.PodTemplate{
2191 {
2192 ObjectMeta: metav1.ObjectMeta{Name: "pod-template-1"},
2193 Template: api.PodTemplateSpec{
2194 ObjectMeta: metav1.ObjectMeta{
2195 Name: "pod-template-2",
2196 Labels: map[string]string{"foo": "bar"},
2197 },
2198 Spec: api.PodSpec{
2199 Containers: []api.Container{},
2200 },
2201 },
2202 },
2203 {
2204 ObjectMeta: metav1.ObjectMeta{Name: "pod-template-2"},
2205 Template: api.PodTemplateSpec{
2206 ObjectMeta: metav1.ObjectMeta{
2207 Name: "pod-template-2",
2208 Labels: map[string]string{"a": "b"},
2209 },
2210 Spec: api.PodSpec{
2211 Containers: []api.Container{},
2212 },
2213 },
2214 },
2215 },
2216 }
2217
2218
2219 expectedRows := []metav1.TableRow{
2220 {Cells: []interface{}{"pod-template-1", "", "", "foo=bar"}},
2221 {Cells: []interface{}{"pod-template-2", "", "", "a=b"}},
2222 }
2223
2224 rows, err := printPodTemplateList(&templateList, printers.GenerateOptions{})
2225 if err != nil {
2226 t.Fatalf("Error printing pod template list: %#v", err)
2227 }
2228 for i := range rows {
2229 rows[i].Object.Object = nil
2230 }
2231 if !reflect.DeepEqual(expectedRows, rows) {
2232 t.Errorf("mismatch: %s", cmp.Diff(expectedRows, rows))
2233 }
2234 }
2235
2236 type stringTestList []struct {
2237 name, got, exp string
2238 }
2239
2240 func TestTranslateTimestampSince(t *testing.T) {
2241 tl := stringTestList{
2242 {"a while from now", translateTimestampSince(metav1.Time{Time: time.Now().Add(2.1e9)}), "<invalid>"},
2243 {"almost now", translateTimestampSince(metav1.Time{Time: time.Now().Add(1.9e9)}), "0s"},
2244 {"now", translateTimestampSince(metav1.Time{Time: time.Now()}), "0s"},
2245 {"unknown", translateTimestampSince(metav1.Time{}), "<unknown>"},
2246 {"30 seconds ago", translateTimestampSince(metav1.Time{Time: time.Now().Add(-3e10)}), "30s"},
2247 {"5 minutes ago", translateTimestampSince(metav1.Time{Time: time.Now().Add(-3e11)}), "5m"},
2248 {"an hour ago", translateTimestampSince(metav1.Time{Time: time.Now().Add(-6e12)}), "100m"},
2249 {"2 days ago", translateTimestampSince(metav1.Time{Time: time.Now().UTC().AddDate(0, 0, -2)}), "2d"},
2250 {"months ago", translateTimestampSince(metav1.Time{Time: time.Now().UTC().AddDate(0, 0, -90)}), "90d"},
2251 {"10 years ago", translateTimestampSince(metav1.Time{Time: time.Now().UTC().AddDate(-10, 0, 0)}), "10y"},
2252 }
2253 for _, test := range tl {
2254 if test.got != test.exp {
2255 t.Errorf("On %v, expected '%v', but got '%v'",
2256 test.name, test.exp, test.got)
2257 }
2258 }
2259 }
2260
2261 func TestTranslateTimestampUntil(t *testing.T) {
2262
2263
2264
2265 const buf = 1e8
2266 tl := stringTestList{
2267 {"a while ago", translateTimestampUntil(metav1.Time{Time: time.Now().Add(-2.1e9)}), "<invalid>"},
2268 {"almost now", translateTimestampUntil(metav1.Time{Time: time.Now().Add(-1.9e9)}), "0s"},
2269 {"now", translateTimestampUntil(metav1.Time{Time: time.Now()}), "0s"},
2270 {"unknown", translateTimestampUntil(metav1.Time{}), "<unknown>"},
2271 {"in 30 seconds", translateTimestampUntil(metav1.Time{Time: time.Now().Add(3e10 + buf)}), "30s"},
2272 {"in 5 minutes", translateTimestampUntil(metav1.Time{Time: time.Now().Add(3e11 + buf)}), "5m"},
2273 {"in an hour", translateTimestampUntil(metav1.Time{Time: time.Now().Add(6e12 + buf)}), "100m"},
2274 {"in 2 days", translateTimestampUntil(metav1.Time{Time: time.Now().UTC().AddDate(0, 0, 2).Add(buf)}), "2d"},
2275 {"in months", translateTimestampUntil(metav1.Time{Time: time.Now().UTC().AddDate(0, 0, 90).Add(buf)}), "90d"},
2276 {"in 10 years", translateTimestampUntil(metav1.Time{Time: time.Now().UTC().AddDate(10, 0, 0).Add(buf)}), "10y"},
2277 }
2278 for _, test := range tl {
2279 if test.got != test.exp {
2280 t.Errorf("On %v, expected '%v', but got '%v'",
2281 test.name, test.exp, test.got)
2282 }
2283 }
2284 }
2285
2286 func TestPrintDeployment(t *testing.T) {
2287
2288 testDeployment := apps.Deployment{
2289 ObjectMeta: metav1.ObjectMeta{
2290 Name: "test1",
2291 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
2292 },
2293 Spec: apps.DeploymentSpec{
2294 Replicas: 5,
2295 Template: api.PodTemplateSpec{
2296 Spec: api.PodSpec{
2297 Containers: []api.Container{
2298 {
2299 Name: "fake-container1",
2300 Image: "fake-image1",
2301 },
2302 {
2303 Name: "fake-container2",
2304 Image: "fake-image2",
2305 },
2306 },
2307 },
2308 },
2309 Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"foo": "bar"}},
2310 },
2311 Status: apps.DeploymentStatus{
2312 Replicas: 10,
2313 UpdatedReplicas: 2,
2314 AvailableReplicas: 1,
2315 UnavailableReplicas: 4,
2316 },
2317 }
2318
2319 tests := []struct {
2320 deployment apps.Deployment
2321 options printers.GenerateOptions
2322 expected []metav1.TableRow
2323 }{
2324
2325 {
2326 deployment: testDeployment,
2327 options: printers.GenerateOptions{},
2328
2329 expected: []metav1.TableRow{{Cells: []interface{}{"test1", "0/5", int64(2), int64(1), "0s"}}},
2330 },
2331
2332 {
2333 deployment: testDeployment,
2334 options: printers.GenerateOptions{Wide: true},
2335
2336 expected: []metav1.TableRow{{Cells: []interface{}{"test1", "0/5", int64(2), int64(1), "0s", "fake-container1,fake-container2", "fake-image1,fake-image2", "foo=bar"}}},
2337 },
2338 }
2339
2340 for i, test := range tests {
2341 rows, err := printDeployment(&test.deployment, test.options)
2342 if err != nil {
2343 t.Fatal(err)
2344 }
2345 for i := range rows {
2346 rows[i].Object.Object = nil
2347 }
2348 if !reflect.DeepEqual(test.expected, rows) {
2349 t.Errorf("%d mismatch: %s", i, cmp.Diff(test.expected, rows))
2350 }
2351 }
2352 }
2353
2354 func TestPrintDaemonSet(t *testing.T) {
2355
2356 testDaemonSet := apps.DaemonSet{
2357 ObjectMeta: metav1.ObjectMeta{
2358 Name: "test1",
2359 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
2360 },
2361 Spec: apps.DaemonSetSpec{
2362 Template: api.PodTemplateSpec{
2363 Spec: api.PodSpec{
2364 Containers: []api.Container{
2365 {
2366 Name: "fake-container1",
2367 Image: "fake-image1",
2368 },
2369 {
2370 Name: "fake-container2",
2371 Image: "fake-image2",
2372 },
2373 },
2374 },
2375 },
2376 Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"foo": "bar"}},
2377 },
2378 Status: apps.DaemonSetStatus{
2379 CurrentNumberScheduled: 2,
2380 DesiredNumberScheduled: 3,
2381 NumberReady: 1,
2382 UpdatedNumberScheduled: 2,
2383 NumberAvailable: 0,
2384 },
2385 }
2386
2387 tests := []struct {
2388 daemonSet apps.DaemonSet
2389 options printers.GenerateOptions
2390 expected []metav1.TableRow
2391 }{
2392
2393 {
2394 daemonSet: testDaemonSet,
2395 options: printers.GenerateOptions{},
2396
2397 expected: []metav1.TableRow{{Cells: []interface{}{"test1", int64(3), int64(2), int64(1), int64(2), int64(0), "<none>", "0s"}}},
2398 },
2399
2400 {
2401 daemonSet: testDaemonSet,
2402 options: printers.GenerateOptions{Wide: true},
2403
2404 expected: []metav1.TableRow{{Cells: []interface{}{"test1", int64(3), int64(2), int64(1), int64(2), int64(0), "<none>", "0s", "fake-container1,fake-container2", "fake-image1,fake-image2", "foo=bar"}}},
2405 },
2406 }
2407
2408 for i, test := range tests {
2409 rows, err := printDaemonSet(&test.daemonSet, test.options)
2410 if err != nil {
2411 t.Fatal(err)
2412 }
2413 for i := range rows {
2414 rows[i].Object.Object = nil
2415 }
2416 if !reflect.DeepEqual(test.expected, rows) {
2417 t.Errorf("%d mismatch: %s", i, cmp.Diff(test.expected, rows))
2418 }
2419 }
2420 }
2421
2422 func TestPrintDaemonSetList(t *testing.T) {
2423
2424 daemonSetList := apps.DaemonSetList{
2425 Items: []apps.DaemonSet{
2426 {
2427 ObjectMeta: metav1.ObjectMeta{
2428 Name: "daemonset1",
2429 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
2430 },
2431 Spec: apps.DaemonSetSpec{
2432 Template: api.PodTemplateSpec{
2433 Spec: api.PodSpec{
2434 Containers: []api.Container{
2435 {
2436 Name: "fake-container1",
2437 Image: "fake-image1",
2438 },
2439 {
2440 Name: "fake-container2",
2441 Image: "fake-image2",
2442 },
2443 },
2444 },
2445 },
2446 },
2447 Status: apps.DaemonSetStatus{
2448 CurrentNumberScheduled: 2,
2449 DesiredNumberScheduled: 3,
2450 NumberReady: 1,
2451 UpdatedNumberScheduled: 2,
2452 NumberAvailable: 0,
2453 },
2454 },
2455 {
2456 ObjectMeta: metav1.ObjectMeta{
2457 Name: "daemonset2",
2458 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
2459 },
2460 Spec: apps.DaemonSetSpec{
2461 Template: api.PodTemplateSpec{},
2462 Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"foo": "bar"}},
2463 },
2464 Status: apps.DaemonSetStatus{
2465 CurrentNumberScheduled: 4,
2466 DesiredNumberScheduled: 2,
2467 NumberReady: 9,
2468 UpdatedNumberScheduled: 3,
2469 NumberAvailable: 3,
2470 },
2471 },
2472 },
2473 }
2474
2475
2476 expectedRows := []metav1.TableRow{
2477 {Cells: []interface{}{"daemonset1", int64(3), int64(2), int64(1), int64(2), int64(0), "<none>", "0s"}},
2478 {Cells: []interface{}{"daemonset2", int64(2), int64(4), int64(9), int64(3), int64(3), "<none>", "0s"}},
2479 }
2480
2481 rows, err := printDaemonSetList(&daemonSetList, printers.GenerateOptions{})
2482 if err != nil {
2483 t.Fatalf("Error printing daemon set list: %#v", err)
2484 }
2485 for i := range rows {
2486 rows[i].Object.Object = nil
2487 }
2488 if !reflect.DeepEqual(expectedRows, rows) {
2489 t.Errorf("mismatch: %s", cmp.Diff(expectedRows, rows))
2490 }
2491 }
2492
2493 func TestPrintJob(t *testing.T) {
2494 now := time.Now()
2495 completions := int32(2)
2496 tests := []struct {
2497 job batch.Job
2498 options printers.GenerateOptions
2499 expected []metav1.TableRow
2500 }{
2501 {
2502
2503 job: batch.Job{
2504 ObjectMeta: metav1.ObjectMeta{
2505 Name: "job1",
2506 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
2507 },
2508 Spec: batch.JobSpec{
2509 Completions: &completions,
2510 Template: api.PodTemplateSpec{
2511 Spec: api.PodSpec{
2512 Containers: []api.Container{
2513 {
2514 Name: "fake-job-container1",
2515 Image: "fake-job-image1",
2516 },
2517 {
2518 Name: "fake-job-container2",
2519 Image: "fake-job-image2",
2520 },
2521 },
2522 },
2523 },
2524 Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"job-label": "job-lable-value"}},
2525 },
2526 Status: batch.JobStatus{
2527 Succeeded: 1,
2528 },
2529 },
2530 options: printers.GenerateOptions{},
2531
2532 expected: []metav1.TableRow{{Cells: []interface{}{"job1", "Running", "1/2", "", "0s"}}},
2533 },
2534
2535 {
2536 job: batch.Job{
2537 ObjectMeta: metav1.ObjectMeta{
2538 Name: "job1",
2539 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
2540 },
2541 Spec: batch.JobSpec{
2542 Completions: &completions,
2543 Template: api.PodTemplateSpec{
2544 Spec: api.PodSpec{
2545 Containers: []api.Container{
2546 {
2547 Name: "fake-job-container1",
2548 Image: "fake-job-image1",
2549 },
2550 {
2551 Name: "fake-job-container2",
2552 Image: "fake-job-image2",
2553 },
2554 },
2555 },
2556 },
2557 Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"job-label": "job-label-value"}},
2558 },
2559 Status: batch.JobStatus{
2560 Succeeded: 1,
2561 },
2562 },
2563 options: printers.GenerateOptions{Wide: true},
2564
2565 expected: []metav1.TableRow{
2566 {
2567 Cells: []interface{}{"job1", "Running", "1/2", "", "0s", "fake-job-container1,fake-job-container2", "fake-job-image1,fake-job-image2", "job-label=job-label-value"},
2568 },
2569 },
2570 },
2571
2572 {
2573 job: batch.Job{
2574 ObjectMeta: metav1.ObjectMeta{
2575 Name: "job2",
2576 CreationTimestamp: metav1.Time{Time: time.Now().AddDate(-10, 0, 0)},
2577 },
2578 Spec: batch.JobSpec{
2579 Completions: nil,
2580 },
2581 Status: batch.JobStatus{
2582 Succeeded: 0,
2583 },
2584 },
2585 options: printers.GenerateOptions{},
2586
2587 expected: []metav1.TableRow{{Cells: []interface{}{"job2", "Running", "0/1", "", "10y"}}},
2588 },
2589
2590 {
2591 job: batch.Job{
2592 ObjectMeta: metav1.ObjectMeta{
2593 Name: "job3",
2594 CreationTimestamp: metav1.Time{Time: time.Now().AddDate(-10, 0, 0)},
2595 },
2596 Spec: batch.JobSpec{
2597 Completions: nil,
2598 },
2599 Status: batch.JobStatus{
2600 Succeeded: 0,
2601 StartTime: &metav1.Time{Time: now.Add(time.Minute)},
2602 CompletionTime: &metav1.Time{Time: now.Add(31 * time.Minute)},
2603 },
2604 },
2605 options: printers.GenerateOptions{},
2606
2607 expected: []metav1.TableRow{{Cells: []interface{}{"job3", "Running", "0/1", "30m", "10y"}}},
2608 },
2609 {
2610 job: batch.Job{
2611 ObjectMeta: metav1.ObjectMeta{
2612 Name: "job4",
2613 CreationTimestamp: metav1.Time{Time: time.Now().AddDate(-10, 0, 0)},
2614 },
2615 Spec: batch.JobSpec{
2616 Completions: nil,
2617 },
2618 Status: batch.JobStatus{
2619 Succeeded: 0,
2620 StartTime: &metav1.Time{Time: time.Now().Add(-20 * time.Minute)},
2621 },
2622 },
2623 options: printers.GenerateOptions{},
2624
2625 expected: []metav1.TableRow{{Cells: []interface{}{"job4", "Running", "0/1", "20m", "10y"}}},
2626 },
2627 {
2628 job: batch.Job{
2629 ObjectMeta: metav1.ObjectMeta{
2630 Name: "job5",
2631 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
2632 },
2633 Spec: batch.JobSpec{
2634 Completions: nil,
2635 },
2636 Status: batch.JobStatus{
2637 Succeeded: 0,
2638 Conditions: []batch.JobCondition{
2639 {
2640 Type: batch.JobComplete,
2641 Status: api.ConditionTrue,
2642 },
2643 },
2644 },
2645 },
2646 options: printers.GenerateOptions{},
2647
2648 expected: []metav1.TableRow{{Cells: []interface{}{"job5", "Complete", "0/1", "", "0s"}}},
2649 },
2650 {
2651 job: batch.Job{
2652 ObjectMeta: metav1.ObjectMeta{
2653 Name: "job6",
2654 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
2655 },
2656 Spec: batch.JobSpec{
2657 Completions: nil,
2658 },
2659 Status: batch.JobStatus{
2660 Succeeded: 0,
2661 Conditions: []batch.JobCondition{
2662 {
2663 Type: batch.JobFailed,
2664 Status: api.ConditionTrue,
2665 },
2666 },
2667 },
2668 },
2669 options: printers.GenerateOptions{},
2670
2671 expected: []metav1.TableRow{{Cells: []interface{}{"job6", "Failed", "0/1", "", "0s"}}},
2672 },
2673 {
2674 job: batch.Job{
2675 ObjectMeta: metav1.ObjectMeta{
2676 Name: "job7",
2677 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
2678 },
2679 Spec: batch.JobSpec{
2680 Completions: nil,
2681 },
2682 Status: batch.JobStatus{
2683 Succeeded: 0,
2684 Conditions: []batch.JobCondition{
2685 {
2686 Type: batch.JobSuspended,
2687 Status: api.ConditionTrue,
2688 },
2689 },
2690 },
2691 },
2692 options: printers.GenerateOptions{},
2693
2694 expected: []metav1.TableRow{{Cells: []interface{}{"job7", "Suspended", "0/1", "", "0s"}}},
2695 },
2696 {
2697 job: batch.Job{
2698 ObjectMeta: metav1.ObjectMeta{
2699 Name: "job8",
2700 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
2701 },
2702 Spec: batch.JobSpec{
2703 Completions: nil,
2704 },
2705 Status: batch.JobStatus{
2706 Succeeded: 0,
2707 Conditions: []batch.JobCondition{
2708 {
2709 Type: batch.JobFailureTarget,
2710 Status: api.ConditionTrue,
2711 },
2712 },
2713 },
2714 },
2715 options: printers.GenerateOptions{},
2716
2717 expected: []metav1.TableRow{{Cells: []interface{}{"job8", "FailureTarget", "0/1", "", "0s"}}},
2718 },
2719 {
2720 job: batch.Job{
2721 ObjectMeta: metav1.ObjectMeta{
2722 Name: "job9",
2723 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
2724 DeletionTimestamp: &metav1.Time{Time: time.Now().Add(1.9e9)},
2725 },
2726 Spec: batch.JobSpec{
2727 Completions: nil,
2728 },
2729 },
2730 options: printers.GenerateOptions{},
2731
2732 expected: []metav1.TableRow{{Cells: []interface{}{"job9", "Terminating", "0/1", "", "0s"}}},
2733 },
2734 }
2735
2736 for i, test := range tests {
2737 rows, err := printJob(&test.job, test.options)
2738 if err != nil {
2739 t.Fatal(err)
2740 }
2741 for i := range rows {
2742 rows[i].Object.Object = nil
2743 }
2744 if !reflect.DeepEqual(test.expected, rows) {
2745 t.Errorf("%d mismatch: %s", i, cmp.Diff(test.expected, rows))
2746 }
2747 }
2748 }
2749
2750 func TestPrintJobList(t *testing.T) {
2751 completions := int32(2)
2752 jobList := batch.JobList{
2753 Items: []batch.Job{
2754 {
2755 ObjectMeta: metav1.ObjectMeta{
2756 Name: "job1",
2757 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
2758 },
2759 Spec: batch.JobSpec{
2760 Completions: &completions,
2761 Template: api.PodTemplateSpec{
2762 Spec: api.PodSpec{
2763 Containers: []api.Container{
2764 {
2765 Name: "fake-job-container1",
2766 Image: "fake-job-image1",
2767 },
2768 {
2769 Name: "fake-job-container2",
2770 Image: "fake-job-image2",
2771 },
2772 },
2773 },
2774 },
2775 Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"job-label": "job-lable-value"}},
2776 },
2777 Status: batch.JobStatus{
2778 Succeeded: 1,
2779 },
2780 },
2781 {
2782 ObjectMeta: metav1.ObjectMeta{
2783 Name: "job2",
2784 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
2785 },
2786 Spec: batch.JobSpec{
2787 Completions: &completions,
2788 Template: api.PodTemplateSpec{
2789 Spec: api.PodSpec{
2790 Containers: []api.Container{
2791 {
2792 Name: "fake-job-container1",
2793 Image: "fake-job-image1",
2794 },
2795 {
2796 Name: "fake-job-container2",
2797 Image: "fake-job-image2",
2798 },
2799 },
2800 },
2801 },
2802 Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"job-label": "job-lable-value"}},
2803 },
2804 Status: batch.JobStatus{
2805 Succeeded: 2,
2806 StartTime: &metav1.Time{Time: time.Now().Add(-20 * time.Minute)},
2807 },
2808 },
2809 },
2810 }
2811
2812
2813 expectedRows := []metav1.TableRow{
2814 {Cells: []interface{}{"job1", "Running", "1/2", "", "0s"}},
2815 {Cells: []interface{}{"job2", "Running", "2/2", "20m", "0s"}},
2816 }
2817
2818 rows, err := printJobList(&jobList, printers.GenerateOptions{})
2819 if err != nil {
2820 t.Fatalf("Error printing job list: %#v", err)
2821 }
2822 for i := range rows {
2823 rows[i].Object.Object = nil
2824 }
2825 if !reflect.DeepEqual(expectedRows, rows) {
2826 t.Errorf("mismatch: %s", cmp.Diff(expectedRows, rows))
2827 }
2828 }
2829
2830 func TestPrintHPA(t *testing.T) {
2831 minReplicasVal := int32(2)
2832 targetUtilizationVal := int32(80)
2833 currentUtilizationVal := int32(50)
2834 metricLabelSelector, err := metav1.ParseToLabelSelector("label=value")
2835 if err != nil {
2836 t.Errorf("unable to parse label selector: %v", err)
2837 }
2838 tests := []struct {
2839 hpa autoscaling.HorizontalPodAutoscaler
2840 expected []metav1.TableRow
2841 }{
2842
2843 {
2844 hpa: autoscaling.HorizontalPodAutoscaler{
2845 ObjectMeta: metav1.ObjectMeta{Name: "some-hpa"},
2846 Spec: autoscaling.HorizontalPodAutoscalerSpec{
2847 ScaleTargetRef: autoscaling.CrossVersionObjectReference{
2848 Name: "some-rc",
2849 Kind: "ReplicationController",
2850 },
2851 MaxReplicas: 10,
2852 },
2853 Status: autoscaling.HorizontalPodAutoscalerStatus{
2854 CurrentReplicas: 4,
2855 DesiredReplicas: 5,
2856 },
2857 },
2858
2859 expected: []metav1.TableRow{{Cells: []interface{}{"some-hpa", "ReplicationController/some-rc", "<none>", "<unset>", int64(10), int64(4), "<unknown>"}}},
2860 },
2861
2862 {
2863 hpa: autoscaling.HorizontalPodAutoscaler{
2864 ObjectMeta: metav1.ObjectMeta{Name: "some-hpa"},
2865 Spec: autoscaling.HorizontalPodAutoscalerSpec{
2866 ScaleTargetRef: autoscaling.CrossVersionObjectReference{
2867 Name: "some-rc",
2868 Kind: "ReplicationController",
2869 },
2870 MinReplicas: &minReplicasVal,
2871 MaxReplicas: 10,
2872 Metrics: []autoscaling.MetricSpec{
2873 {
2874 Type: autoscaling.ExternalMetricSourceType,
2875 External: &autoscaling.ExternalMetricSource{
2876 Metric: autoscaling.MetricIdentifier{
2877 Name: "some-external-metric",
2878 Selector: metricLabelSelector,
2879 },
2880 Target: autoscaling.MetricTarget{
2881 Type: autoscaling.AverageValueMetricType,
2882 AverageValue: resource.NewMilliQuantity(100, resource.DecimalSI),
2883 },
2884 },
2885 },
2886 },
2887 },
2888 Status: autoscaling.HorizontalPodAutoscalerStatus{
2889 CurrentReplicas: 4,
2890 DesiredReplicas: 5,
2891 },
2892 },
2893
2894 expected: []metav1.TableRow{{Cells: []interface{}{"some-hpa", "ReplicationController/some-rc", "<unknown>/100m (avg)", "2", int64(10), int64(4), "<unknown>"}}},
2895 },
2896
2897 {
2898 hpa: autoscaling.HorizontalPodAutoscaler{
2899 ObjectMeta: metav1.ObjectMeta{Name: "some-hpa"},
2900 Spec: autoscaling.HorizontalPodAutoscalerSpec{
2901 ScaleTargetRef: autoscaling.CrossVersionObjectReference{
2902 Name: "some-rc",
2903 Kind: "ReplicationController",
2904 },
2905 MinReplicas: &minReplicasVal,
2906 MaxReplicas: 10,
2907 Metrics: []autoscaling.MetricSpec{
2908 {
2909 Type: autoscaling.ExternalMetricSourceType,
2910 External: &autoscaling.ExternalMetricSource{
2911 Metric: autoscaling.MetricIdentifier{
2912 Name: "some-external-metric",
2913 Selector: metricLabelSelector,
2914 },
2915 Target: autoscaling.MetricTarget{
2916 Type: autoscaling.AverageValueMetricType,
2917 AverageValue: resource.NewMilliQuantity(100, resource.DecimalSI),
2918 },
2919 },
2920 },
2921 },
2922 },
2923 Status: autoscaling.HorizontalPodAutoscalerStatus{
2924 CurrentReplicas: 4,
2925 DesiredReplicas: 5,
2926 CurrentMetrics: []autoscaling.MetricStatus{
2927 {
2928 Type: autoscaling.ExternalMetricSourceType,
2929 External: &autoscaling.ExternalMetricStatus{
2930 Metric: autoscaling.MetricIdentifier{
2931 Name: "some-external-metric",
2932 Selector: metricLabelSelector,
2933 },
2934 Current: autoscaling.MetricValueStatus{
2935 AverageValue: resource.NewMilliQuantity(50, resource.DecimalSI),
2936 },
2937 },
2938 },
2939 },
2940 },
2941 },
2942
2943 expected: []metav1.TableRow{{Cells: []interface{}{"some-hpa", "ReplicationController/some-rc", "50m/100m (avg)", "2", int64(10), int64(4), "<unknown>"}}},
2944 },
2945
2946 {
2947 hpa: autoscaling.HorizontalPodAutoscaler{
2948 ObjectMeta: metav1.ObjectMeta{Name: "some-hpa"},
2949 Spec: autoscaling.HorizontalPodAutoscalerSpec{
2950 ScaleTargetRef: autoscaling.CrossVersionObjectReference{
2951 Name: "some-rc",
2952 Kind: "ReplicationController",
2953 },
2954 MinReplicas: &minReplicasVal,
2955 MaxReplicas: 10,
2956 Metrics: []autoscaling.MetricSpec{
2957 {
2958 Type: autoscaling.ExternalMetricSourceType,
2959 External: &autoscaling.ExternalMetricSource{
2960 Metric: autoscaling.MetricIdentifier{
2961 Name: "some-service-metric",
2962 Selector: metricLabelSelector,
2963 },
2964 Target: autoscaling.MetricTarget{
2965 Type: autoscaling.ValueMetricType,
2966 Value: resource.NewMilliQuantity(100, resource.DecimalSI),
2967 },
2968 },
2969 },
2970 },
2971 },
2972 Status: autoscaling.HorizontalPodAutoscalerStatus{
2973 CurrentReplicas: 4,
2974 DesiredReplicas: 5,
2975 },
2976 },
2977
2978 expected: []metav1.TableRow{{Cells: []interface{}{"some-hpa", "ReplicationController/some-rc", "<unknown>/100m", "2", int64(10), int64(4), "<unknown>"}}},
2979 },
2980
2981 {
2982 hpa: autoscaling.HorizontalPodAutoscaler{
2983 ObjectMeta: metav1.ObjectMeta{Name: "some-hpa"},
2984 Spec: autoscaling.HorizontalPodAutoscalerSpec{
2985 ScaleTargetRef: autoscaling.CrossVersionObjectReference{
2986 Name: "some-rc",
2987 Kind: "ReplicationController",
2988 },
2989 MinReplicas: &minReplicasVal,
2990 MaxReplicas: 10,
2991 Metrics: []autoscaling.MetricSpec{
2992 {
2993 Type: autoscaling.ExternalMetricSourceType,
2994 External: &autoscaling.ExternalMetricSource{
2995 Metric: autoscaling.MetricIdentifier{
2996 Name: "some-external-metric",
2997 Selector: metricLabelSelector,
2998 },
2999 Target: autoscaling.MetricTarget{
3000 Type: autoscaling.ValueMetricType,
3001 Value: resource.NewMilliQuantity(100, resource.DecimalSI),
3002 },
3003 },
3004 },
3005 },
3006 },
3007 Status: autoscaling.HorizontalPodAutoscalerStatus{
3008 CurrentReplicas: 4,
3009 DesiredReplicas: 5,
3010 CurrentMetrics: []autoscaling.MetricStatus{
3011 {
3012 Type: autoscaling.ExternalMetricSourceType,
3013 External: &autoscaling.ExternalMetricStatus{
3014 Metric: autoscaling.MetricIdentifier{
3015 Name: "some-external-metric",
3016 },
3017 Current: autoscaling.MetricValueStatus{
3018 Value: resource.NewMilliQuantity(50, resource.DecimalSI),
3019 },
3020 },
3021 },
3022 },
3023 },
3024 },
3025
3026 expected: []metav1.TableRow{{Cells: []interface{}{"some-hpa", "ReplicationController/some-rc", "50m/100m", "2", int64(10), int64(4), "<unknown>"}}},
3027 },
3028
3029 {
3030 hpa: autoscaling.HorizontalPodAutoscaler{
3031 ObjectMeta: metav1.ObjectMeta{Name: "some-hpa"},
3032 Spec: autoscaling.HorizontalPodAutoscalerSpec{
3033 ScaleTargetRef: autoscaling.CrossVersionObjectReference{
3034 Name: "some-rc",
3035 Kind: "ReplicationController",
3036 },
3037 MinReplicas: &minReplicasVal,
3038 MaxReplicas: 10,
3039 Metrics: []autoscaling.MetricSpec{
3040 {
3041 Type: autoscaling.PodsMetricSourceType,
3042 Pods: &autoscaling.PodsMetricSource{
3043 Metric: autoscaling.MetricIdentifier{
3044 Name: "some-pods-metric",
3045 },
3046 Target: autoscaling.MetricTarget{
3047 Type: autoscaling.AverageValueMetricType,
3048 AverageValue: resource.NewMilliQuantity(100, resource.DecimalSI),
3049 },
3050 },
3051 },
3052 },
3053 },
3054 Status: autoscaling.HorizontalPodAutoscalerStatus{
3055 CurrentReplicas: 4,
3056 DesiredReplicas: 5,
3057 },
3058 },
3059
3060 expected: []metav1.TableRow{{Cells: []interface{}{"some-hpa", "ReplicationController/some-rc", "<unknown>/100m", "2", int64(10), int64(4), "<unknown>"}}},
3061 },
3062
3063 {
3064 hpa: autoscaling.HorizontalPodAutoscaler{
3065 ObjectMeta: metav1.ObjectMeta{Name: "some-hpa"},
3066 Spec: autoscaling.HorizontalPodAutoscalerSpec{
3067 ScaleTargetRef: autoscaling.CrossVersionObjectReference{
3068 Name: "some-rc",
3069 Kind: "ReplicationController",
3070 },
3071 MinReplicas: &minReplicasVal,
3072 MaxReplicas: 10,
3073 Metrics: []autoscaling.MetricSpec{
3074 {
3075 Type: autoscaling.PodsMetricSourceType,
3076 Pods: &autoscaling.PodsMetricSource{
3077 Metric: autoscaling.MetricIdentifier{
3078 Name: "some-pods-metric",
3079 },
3080 Target: autoscaling.MetricTarget{
3081 Type: autoscaling.AverageValueMetricType,
3082 AverageValue: resource.NewMilliQuantity(100, resource.DecimalSI),
3083 },
3084 },
3085 },
3086 },
3087 },
3088 Status: autoscaling.HorizontalPodAutoscalerStatus{
3089 CurrentReplicas: 4,
3090 DesiredReplicas: 5,
3091 CurrentMetrics: []autoscaling.MetricStatus{
3092 {
3093 Type: autoscaling.PodsMetricSourceType,
3094 Pods: &autoscaling.PodsMetricStatus{
3095 Metric: autoscaling.MetricIdentifier{
3096 Name: "some-pods-metric",
3097 },
3098 Current: autoscaling.MetricValueStatus{
3099 AverageValue: resource.NewMilliQuantity(50, resource.DecimalSI),
3100 },
3101 },
3102 },
3103 },
3104 },
3105 },
3106
3107 expected: []metav1.TableRow{{Cells: []interface{}{"some-hpa", "ReplicationController/some-rc", "50m/100m", "2", int64(10), int64(4), "<unknown>"}}},
3108 },
3109
3110 {
3111 hpa: autoscaling.HorizontalPodAutoscaler{
3112 ObjectMeta: metav1.ObjectMeta{Name: "some-hpa"},
3113 Spec: autoscaling.HorizontalPodAutoscalerSpec{
3114 ScaleTargetRef: autoscaling.CrossVersionObjectReference{
3115 Name: "some-rc",
3116 Kind: "ReplicationController",
3117 },
3118 MinReplicas: &minReplicasVal,
3119 MaxReplicas: 10,
3120 Metrics: []autoscaling.MetricSpec{
3121 {
3122 Type: autoscaling.ObjectMetricSourceType,
3123 Object: &autoscaling.ObjectMetricSource{
3124 DescribedObject: autoscaling.CrossVersionObjectReference{
3125 Name: "some-service",
3126 Kind: "Service",
3127 },
3128 Metric: autoscaling.MetricIdentifier{
3129 Name: "some-service-metric",
3130 },
3131 Target: autoscaling.MetricTarget{
3132 Type: autoscaling.ValueMetricType,
3133 Value: resource.NewMilliQuantity(100, resource.DecimalSI),
3134 },
3135 },
3136 },
3137 },
3138 },
3139 Status: autoscaling.HorizontalPodAutoscalerStatus{
3140 CurrentReplicas: 4,
3141 DesiredReplicas: 5,
3142 },
3143 },
3144
3145 expected: []metav1.TableRow{{Cells: []interface{}{"some-hpa", "ReplicationController/some-rc", "<unknown>/100m", "2", int64(10), int64(4), "<unknown>"}}},
3146 },
3147
3148 {
3149 hpa: autoscaling.HorizontalPodAutoscaler{
3150 ObjectMeta: metav1.ObjectMeta{Name: "some-hpa"},
3151 Spec: autoscaling.HorizontalPodAutoscalerSpec{
3152 ScaleTargetRef: autoscaling.CrossVersionObjectReference{
3153 Name: "some-rc",
3154 Kind: "ReplicationController",
3155 },
3156 MinReplicas: &minReplicasVal,
3157 MaxReplicas: 10,
3158 Metrics: []autoscaling.MetricSpec{
3159 {
3160 Type: autoscaling.ObjectMetricSourceType,
3161 Object: &autoscaling.ObjectMetricSource{
3162 DescribedObject: autoscaling.CrossVersionObjectReference{
3163 Name: "some-service",
3164 Kind: "Service",
3165 },
3166 Metric: autoscaling.MetricIdentifier{
3167 Name: "some-service-metric",
3168 },
3169 Target: autoscaling.MetricTarget{
3170 Type: autoscaling.ValueMetricType,
3171 Value: resource.NewMilliQuantity(100, resource.DecimalSI),
3172 },
3173 },
3174 },
3175 },
3176 },
3177 Status: autoscaling.HorizontalPodAutoscalerStatus{
3178 CurrentReplicas: 4,
3179 DesiredReplicas: 5,
3180 CurrentMetrics: []autoscaling.MetricStatus{
3181 {
3182 Type: autoscaling.ObjectMetricSourceType,
3183 Object: &autoscaling.ObjectMetricStatus{
3184 DescribedObject: autoscaling.CrossVersionObjectReference{
3185 Name: "some-service",
3186 Kind: "Service",
3187 },
3188 Metric: autoscaling.MetricIdentifier{
3189 Name: "some-service-metric",
3190 },
3191 Current: autoscaling.MetricValueStatus{
3192 Value: resource.NewMilliQuantity(50, resource.DecimalSI),
3193 },
3194 },
3195 },
3196 },
3197 },
3198 },
3199
3200 expected: []metav1.TableRow{{Cells: []interface{}{"some-hpa", "ReplicationController/some-rc", "50m/100m", "2", int64(10), int64(4), "<unknown>"}}},
3201 },
3202
3203 {
3204 hpa: autoscaling.HorizontalPodAutoscaler{
3205 ObjectMeta: metav1.ObjectMeta{Name: "some-hpa"},
3206 Spec: autoscaling.HorizontalPodAutoscalerSpec{
3207 ScaleTargetRef: autoscaling.CrossVersionObjectReference{
3208 Name: "some-rc",
3209 Kind: "ReplicationController",
3210 },
3211 MinReplicas: &minReplicasVal,
3212 MaxReplicas: 10,
3213 Metrics: []autoscaling.MetricSpec{
3214 {
3215 Type: autoscaling.ResourceMetricSourceType,
3216 Resource: &autoscaling.ResourceMetricSource{
3217 Name: api.ResourceCPU,
3218 Target: autoscaling.MetricTarget{
3219 Type: autoscaling.AverageValueMetricType,
3220 AverageValue: resource.NewMilliQuantity(100, resource.DecimalSI),
3221 },
3222 },
3223 },
3224 },
3225 },
3226 Status: autoscaling.HorizontalPodAutoscalerStatus{
3227 CurrentReplicas: 4,
3228 DesiredReplicas: 5,
3229 },
3230 },
3231
3232 expected: []metav1.TableRow{{Cells: []interface{}{"some-hpa", "ReplicationController/some-rc", "cpu: <unknown>/100m", "2", int64(10), int64(4), "<unknown>"}}},
3233 },
3234
3235 {
3236 hpa: autoscaling.HorizontalPodAutoscaler{
3237 ObjectMeta: metav1.ObjectMeta{Name: "some-hpa"},
3238 Spec: autoscaling.HorizontalPodAutoscalerSpec{
3239 ScaleTargetRef: autoscaling.CrossVersionObjectReference{
3240 Name: "some-rc",
3241 Kind: "ReplicationController",
3242 },
3243 MinReplicas: &minReplicasVal,
3244 MaxReplicas: 10,
3245 Metrics: []autoscaling.MetricSpec{
3246 {
3247 Type: autoscaling.ResourceMetricSourceType,
3248 Resource: &autoscaling.ResourceMetricSource{
3249 Name: api.ResourceCPU,
3250 Target: autoscaling.MetricTarget{
3251 Type: autoscaling.AverageValueMetricType,
3252 AverageValue: resource.NewMilliQuantity(100, resource.DecimalSI),
3253 },
3254 },
3255 },
3256 },
3257 },
3258 Status: autoscaling.HorizontalPodAutoscalerStatus{
3259 CurrentReplicas: 4,
3260 DesiredReplicas: 5,
3261 CurrentMetrics: []autoscaling.MetricStatus{
3262 {
3263 Type: autoscaling.ResourceMetricSourceType,
3264 Resource: &autoscaling.ResourceMetricStatus{
3265 Name: api.ResourceCPU,
3266 Current: autoscaling.MetricValueStatus{
3267 AverageValue: resource.NewMilliQuantity(50, resource.DecimalSI),
3268 },
3269 },
3270 },
3271 },
3272 },
3273 },
3274
3275 expected: []metav1.TableRow{{Cells: []interface{}{"some-hpa", "ReplicationController/some-rc", "cpu: 50m/100m", "2", int64(10), int64(4), "<unknown>"}}},
3276 },
3277
3278 {
3279 hpa: autoscaling.HorizontalPodAutoscaler{
3280 ObjectMeta: metav1.ObjectMeta{Name: "some-hpa"},
3281 Spec: autoscaling.HorizontalPodAutoscalerSpec{
3282 ScaleTargetRef: autoscaling.CrossVersionObjectReference{
3283 Name: "some-rc",
3284 Kind: "ReplicationController",
3285 },
3286 MinReplicas: &minReplicasVal,
3287 MaxReplicas: 10,
3288 Metrics: []autoscaling.MetricSpec{
3289 {
3290 Type: autoscaling.ResourceMetricSourceType,
3291 Resource: &autoscaling.ResourceMetricSource{
3292 Name: api.ResourceCPU,
3293 Target: autoscaling.MetricTarget{
3294 Type: autoscaling.UtilizationMetricType,
3295 AverageUtilization: &targetUtilizationVal,
3296 },
3297 },
3298 },
3299 },
3300 },
3301 Status: autoscaling.HorizontalPodAutoscalerStatus{
3302 CurrentReplicas: 4,
3303 DesiredReplicas: 5,
3304 },
3305 },
3306
3307 expected: []metav1.TableRow{{Cells: []interface{}{"some-hpa", "ReplicationController/some-rc", "cpu: <unknown>/80%", "2", int64(10), int64(4), "<unknown>"}}},
3308 },
3309
3310 {
3311 hpa: autoscaling.HorizontalPodAutoscaler{
3312 ObjectMeta: metav1.ObjectMeta{Name: "some-hpa"},
3313 Spec: autoscaling.HorizontalPodAutoscalerSpec{
3314 ScaleTargetRef: autoscaling.CrossVersionObjectReference{
3315 Name: "some-rc",
3316 Kind: "ReplicationController",
3317 },
3318 MinReplicas: &minReplicasVal,
3319 MaxReplicas: 10,
3320 Metrics: []autoscaling.MetricSpec{
3321 {
3322 Type: autoscaling.ResourceMetricSourceType,
3323 Resource: &autoscaling.ResourceMetricSource{
3324 Name: api.ResourceCPU,
3325 Target: autoscaling.MetricTarget{
3326 Type: autoscaling.UtilizationMetricType,
3327 AverageUtilization: &targetUtilizationVal,
3328 },
3329 },
3330 },
3331 },
3332 },
3333 Status: autoscaling.HorizontalPodAutoscalerStatus{
3334 CurrentReplicas: 4,
3335 DesiredReplicas: 5,
3336 CurrentMetrics: []autoscaling.MetricStatus{
3337 {
3338 Type: autoscaling.ResourceMetricSourceType,
3339 Resource: &autoscaling.ResourceMetricStatus{
3340 Name: api.ResourceCPU,
3341 Current: autoscaling.MetricValueStatus{
3342 AverageUtilization: ¤tUtilizationVal,
3343 AverageValue: resource.NewMilliQuantity(40, resource.DecimalSI),
3344 },
3345 },
3346 },
3347 },
3348 },
3349 },
3350
3351 expected: []metav1.TableRow{{Cells: []interface{}{"some-hpa", "ReplicationController/some-rc", "cpu: 50%/80%", "2", int64(10), int64(4), "<unknown>"}}},
3352 },
3353
3354 {
3355 hpa: autoscaling.HorizontalPodAutoscaler{
3356 ObjectMeta: metav1.ObjectMeta{Name: "some-hpa"},
3357 Spec: autoscaling.HorizontalPodAutoscalerSpec{
3358 ScaleTargetRef: autoscaling.CrossVersionObjectReference{
3359 Name: "some-rc",
3360 Kind: "ReplicationController",
3361 },
3362 MinReplicas: &minReplicasVal,
3363 MaxReplicas: 10,
3364 Metrics: []autoscaling.MetricSpec{
3365 {
3366 Type: autoscaling.ContainerResourceMetricSourceType,
3367 ContainerResource: &autoscaling.ContainerResourceMetricSource{
3368 Name: api.ResourceCPU,
3369 Container: "application",
3370 Target: autoscaling.MetricTarget{
3371 Type: autoscaling.AverageValueMetricType,
3372 AverageValue: resource.NewMilliQuantity(100, resource.DecimalSI),
3373 },
3374 },
3375 },
3376 },
3377 },
3378 Status: autoscaling.HorizontalPodAutoscalerStatus{
3379 CurrentReplicas: 4,
3380 DesiredReplicas: 5,
3381 },
3382 },
3383
3384 expected: []metav1.TableRow{{Cells: []interface{}{"some-hpa", "ReplicationController/some-rc", "cpu: <unknown>/100m", "2", int64(10), int64(4), "<unknown>"}}},
3385 },
3386
3387 {
3388 hpa: autoscaling.HorizontalPodAutoscaler{
3389 ObjectMeta: metav1.ObjectMeta{Name: "some-hpa"},
3390 Spec: autoscaling.HorizontalPodAutoscalerSpec{
3391 ScaleTargetRef: autoscaling.CrossVersionObjectReference{
3392 Name: "some-rc",
3393 Kind: "ReplicationController",
3394 },
3395 MinReplicas: &minReplicasVal,
3396 MaxReplicas: 10,
3397 Metrics: []autoscaling.MetricSpec{
3398 {
3399 Type: autoscaling.ContainerResourceMetricSourceType,
3400 ContainerResource: &autoscaling.ContainerResourceMetricSource{
3401 Name: api.ResourceCPU,
3402 Target: autoscaling.MetricTarget{
3403 Type: autoscaling.AverageValueMetricType,
3404 AverageValue: resource.NewMilliQuantity(100, resource.DecimalSI),
3405 },
3406 },
3407 },
3408 },
3409 },
3410 Status: autoscaling.HorizontalPodAutoscalerStatus{
3411 CurrentReplicas: 4,
3412 DesiredReplicas: 5,
3413 CurrentMetrics: []autoscaling.MetricStatus{
3414 {
3415 Type: autoscaling.ContainerResourceMetricSourceType,
3416 ContainerResource: &autoscaling.ContainerResourceMetricStatus{
3417 Name: api.ResourceCPU,
3418 Container: "application",
3419 Current: autoscaling.MetricValueStatus{
3420 AverageValue: resource.NewMilliQuantity(50, resource.DecimalSI),
3421 },
3422 },
3423 },
3424 },
3425 },
3426 },
3427
3428 expected: []metav1.TableRow{{Cells: []interface{}{"some-hpa", "ReplicationController/some-rc", "cpu: 50m/100m", "2", int64(10), int64(4), "<unknown>"}}},
3429 },
3430
3431 {
3432 hpa: autoscaling.HorizontalPodAutoscaler{
3433 ObjectMeta: metav1.ObjectMeta{Name: "some-hpa"},
3434 Spec: autoscaling.HorizontalPodAutoscalerSpec{
3435 ScaleTargetRef: autoscaling.CrossVersionObjectReference{
3436 Name: "some-rc",
3437 Kind: "ReplicationController",
3438 },
3439 MinReplicas: &minReplicasVal,
3440 MaxReplicas: 10,
3441 Metrics: []autoscaling.MetricSpec{
3442 {
3443 Type: autoscaling.ContainerResourceMetricSourceType,
3444 ContainerResource: &autoscaling.ContainerResourceMetricSource{
3445 Name: api.ResourceCPU,
3446 Container: "application",
3447 Target: autoscaling.MetricTarget{
3448 Type: autoscaling.UtilizationMetricType,
3449 AverageUtilization: &targetUtilizationVal,
3450 },
3451 },
3452 },
3453 },
3454 },
3455 Status: autoscaling.HorizontalPodAutoscalerStatus{
3456 CurrentReplicas: 4,
3457 DesiredReplicas: 5,
3458 },
3459 },
3460
3461 expected: []metav1.TableRow{{Cells: []interface{}{"some-hpa", "ReplicationController/some-rc", "cpu: <unknown>/80%", "2", int64(10), int64(4), "<unknown>"}}},
3462 },
3463
3464 {
3465 hpa: autoscaling.HorizontalPodAutoscaler{
3466 ObjectMeta: metav1.ObjectMeta{Name: "some-hpa"},
3467 Spec: autoscaling.HorizontalPodAutoscalerSpec{
3468 ScaleTargetRef: autoscaling.CrossVersionObjectReference{
3469 Name: "some-rc",
3470 Kind: "ReplicationController",
3471 },
3472 MinReplicas: &minReplicasVal,
3473 MaxReplicas: 10,
3474 Metrics: []autoscaling.MetricSpec{
3475 {
3476 Type: autoscaling.ContainerResourceMetricSourceType,
3477 ContainerResource: &autoscaling.ContainerResourceMetricSource{
3478 Name: api.ResourceCPU,
3479 Target: autoscaling.MetricTarget{
3480 Type: autoscaling.UtilizationMetricType,
3481 AverageUtilization: &targetUtilizationVal,
3482 },
3483 },
3484 },
3485 },
3486 },
3487 Status: autoscaling.HorizontalPodAutoscalerStatus{
3488 CurrentReplicas: 4,
3489 DesiredReplicas: 5,
3490 CurrentMetrics: []autoscaling.MetricStatus{
3491 {
3492 Type: autoscaling.ContainerResourceMetricSourceType,
3493 ContainerResource: &autoscaling.ContainerResourceMetricStatus{
3494 Name: api.ResourceCPU,
3495 Container: "application",
3496 Current: autoscaling.MetricValueStatus{
3497 AverageUtilization: ¤tUtilizationVal,
3498 AverageValue: resource.NewMilliQuantity(40, resource.DecimalSI),
3499 },
3500 },
3501 },
3502 },
3503 },
3504 },
3505
3506 expected: []metav1.TableRow{{Cells: []interface{}{"some-hpa", "ReplicationController/some-rc", "cpu: 50%/80%", "2", int64(10), int64(4), "<unknown>"}}},
3507 },
3508
3509 {
3510 hpa: autoscaling.HorizontalPodAutoscaler{
3511 ObjectMeta: metav1.ObjectMeta{Name: "some-hpa"},
3512 Spec: autoscaling.HorizontalPodAutoscalerSpec{
3513 ScaleTargetRef: autoscaling.CrossVersionObjectReference{
3514 Name: "some-rc",
3515 Kind: "ReplicationController",
3516 },
3517 MinReplicas: &minReplicasVal,
3518 MaxReplicas: 10,
3519 Metrics: []autoscaling.MetricSpec{
3520 {
3521 Type: autoscaling.PodsMetricSourceType,
3522 Pods: &autoscaling.PodsMetricSource{
3523 Metric: autoscaling.MetricIdentifier{
3524 Name: "some-pods-metric",
3525 },
3526 Target: autoscaling.MetricTarget{
3527 Type: autoscaling.AverageValueMetricType,
3528 AverageValue: resource.NewMilliQuantity(100, resource.DecimalSI),
3529 },
3530 },
3531 },
3532 {
3533 Type: autoscaling.ResourceMetricSourceType,
3534 Resource: &autoscaling.ResourceMetricSource{
3535 Name: api.ResourceCPU,
3536 Target: autoscaling.MetricTarget{
3537 Type: autoscaling.UtilizationMetricType,
3538 AverageUtilization: &targetUtilizationVal,
3539 },
3540 },
3541 },
3542 {
3543 Type: autoscaling.PodsMetricSourceType,
3544 Pods: &autoscaling.PodsMetricSource{
3545 Metric: autoscaling.MetricIdentifier{
3546 Name: "other-pods-metric",
3547 },
3548 Target: autoscaling.MetricTarget{
3549 Type: autoscaling.AverageValueMetricType,
3550 AverageValue: resource.NewMilliQuantity(400, resource.DecimalSI),
3551 },
3552 },
3553 },
3554 },
3555 },
3556 Status: autoscaling.HorizontalPodAutoscalerStatus{
3557 CurrentReplicas: 4,
3558 DesiredReplicas: 5,
3559 CurrentMetrics: []autoscaling.MetricStatus{
3560 {
3561 Type: autoscaling.PodsMetricSourceType,
3562 Pods: &autoscaling.PodsMetricStatus{
3563 Metric: autoscaling.MetricIdentifier{
3564 Name: "some-pods-metric",
3565 },
3566 Current: autoscaling.MetricValueStatus{
3567 AverageValue: resource.NewMilliQuantity(50, resource.DecimalSI),
3568 },
3569 },
3570 },
3571 {
3572 Type: autoscaling.ResourceMetricSourceType,
3573 Resource: &autoscaling.ResourceMetricStatus{
3574 Name: api.ResourceCPU,
3575 Current: autoscaling.MetricValueStatus{
3576 AverageUtilization: ¤tUtilizationVal,
3577 AverageValue: resource.NewMilliQuantity(40, resource.DecimalSI),
3578 },
3579 },
3580 },
3581 },
3582 },
3583 },
3584
3585 expected: []metav1.TableRow{{Cells: []interface{}{"some-hpa", "ReplicationController/some-rc", "50m/100m, cpu: 50%/80% + 1 more...", "2", int64(10), int64(4), "<unknown>"}}},
3586 },
3587 }
3588
3589 for i, test := range tests {
3590 rows, err := printHorizontalPodAutoscaler(&test.hpa, printers.GenerateOptions{})
3591 if err != nil {
3592 t.Fatal(err)
3593 }
3594 for i := range rows {
3595 rows[i].Object.Object = nil
3596 }
3597 if !reflect.DeepEqual(test.expected, rows) {
3598 t.Errorf("%d mismatch: %s", i, cmp.Diff(test.expected, rows))
3599 }
3600 }
3601 }
3602
3603 func TestPrintService(t *testing.T) {
3604 singleExternalIP := []string{"80.11.12.10"}
3605 mulExternalIP := []string{"80.11.12.10", "80.11.12.11"}
3606 tests := []struct {
3607 service api.Service
3608 options printers.GenerateOptions
3609 expected []metav1.TableRow
3610 }{
3611 {
3612
3613 service: api.Service{
3614 ObjectMeta: metav1.ObjectMeta{Name: "test1"},
3615 Spec: api.ServiceSpec{
3616 Type: api.ServiceTypeClusterIP,
3617 Ports: []api.ServicePort{
3618 {
3619 Protocol: "tcp",
3620 Port: 2233,
3621 },
3622 },
3623 ClusterIPs: []string{"10.9.8.7"},
3624 Selector: map[string]string{"foo": "bar"},
3625 },
3626 },
3627 options: printers.GenerateOptions{},
3628
3629 expected: []metav1.TableRow{{Cells: []interface{}{"test1", "ClusterIP", "10.9.8.7", "<none>", "2233/tcp", "<unknown>"}}},
3630 },
3631 {
3632
3633 service: api.Service{
3634 ObjectMeta: metav1.ObjectMeta{Name: "test1"},
3635 Spec: api.ServiceSpec{
3636 Type: api.ServiceTypeClusterIP,
3637 Ports: []api.ServicePort{
3638 {
3639 Protocol: "tcp",
3640 Port: 2233,
3641 },
3642 },
3643 ClusterIPs: []string{"10.9.8.7"},
3644 Selector: map[string]string{"foo": "bar"},
3645 },
3646 },
3647 options: printers.GenerateOptions{Wide: true},
3648
3649 expected: []metav1.TableRow{{Cells: []interface{}{"test1", "ClusterIP", "10.9.8.7", "<none>", "2233/tcp", "<unknown>", "foo=bar"}}},
3650 },
3651 {
3652
3653 service: api.Service{
3654 ObjectMeta: metav1.ObjectMeta{Name: "test2"},
3655 Spec: api.ServiceSpec{
3656 Type: api.ServiceTypeNodePort,
3657 Ports: []api.ServicePort{
3658 {
3659 Protocol: "tcp",
3660 Port: 8888,
3661 NodePort: 9999,
3662 },
3663 },
3664 ClusterIPs: []string{"10.9.8.7"},
3665 },
3666 },
3667 options: printers.GenerateOptions{},
3668
3669 expected: []metav1.TableRow{{Cells: []interface{}{"test2", "NodePort", "10.9.8.7", "<none>", "8888:9999/tcp", "<unknown>"}}},
3670 },
3671 {
3672
3673 service: api.Service{
3674 ObjectMeta: metav1.ObjectMeta{Name: "test3"},
3675 Spec: api.ServiceSpec{
3676 Type: api.ServiceTypeLoadBalancer,
3677 Ports: []api.ServicePort{
3678 {
3679 Protocol: "tcp",
3680 Port: 8888,
3681 },
3682 },
3683 ClusterIPs: []string{"10.9.8.7"},
3684 },
3685 },
3686 options: printers.GenerateOptions{},
3687
3688 expected: []metav1.TableRow{{Cells: []interface{}{"test3", "LoadBalancer", "10.9.8.7", "<pending>", "8888/tcp", "<unknown>"}}},
3689 },
3690 {
3691
3692 service: api.Service{
3693 ObjectMeta: metav1.ObjectMeta{Name: "test4"},
3694 Spec: api.ServiceSpec{
3695 Type: api.ServiceTypeLoadBalancer,
3696 Ports: []api.ServicePort{
3697 {
3698 Protocol: "tcp",
3699 Port: 8888,
3700 },
3701 },
3702 ClusterIPs: []string{"10.9.8.7"},
3703 ExternalIPs: singleExternalIP,
3704 },
3705 },
3706 options: printers.GenerateOptions{},
3707
3708 expected: []metav1.TableRow{{Cells: []interface{}{"test4", "LoadBalancer", "10.9.8.7", "80.11.12.10", "8888/tcp", "<unknown>"}}},
3709 },
3710 {
3711
3712 service: api.Service{
3713 ObjectMeta: metav1.ObjectMeta{Name: "test5"},
3714 Spec: api.ServiceSpec{
3715 Type: api.ServiceTypeLoadBalancer,
3716 Ports: []api.ServicePort{
3717 {
3718 Protocol: "tcp",
3719 Port: 8888,
3720 },
3721 },
3722 ClusterIPs: []string{"10.9.8.7"},
3723 ExternalIPs: singleExternalIP,
3724 },
3725 Status: api.ServiceStatus{
3726 LoadBalancer: api.LoadBalancerStatus{
3727 Ingress: []api.LoadBalancerIngress{
3728 {
3729 IP: "3.4.5.6",
3730 Hostname: "test.cluster.com",
3731 },
3732 },
3733 },
3734 },
3735 },
3736 options: printers.GenerateOptions{},
3737
3738 expected: []metav1.TableRow{{Cells: []interface{}{"test5", "LoadBalancer", "10.9.8.7", "3.4.5.6,80.11.12.10", "8888/tcp", "<unknown>"}}},
3739 },
3740 {
3741
3742 service: api.Service{
3743 ObjectMeta: metav1.ObjectMeta{Name: "test6"},
3744 Spec: api.ServiceSpec{
3745 Type: api.ServiceTypeLoadBalancer,
3746 Ports: []api.ServicePort{
3747 {
3748 Protocol: "tcp",
3749 Port: 8888,
3750 },
3751 },
3752 ClusterIPs: []string{"10.9.8.7"},
3753 ExternalIPs: mulExternalIP,
3754 },
3755 Status: api.ServiceStatus{
3756 LoadBalancer: api.LoadBalancerStatus{
3757 Ingress: []api.LoadBalancerIngress{
3758 {
3759 IP: "2.3.4.5",
3760 Hostname: "test.cluster.local",
3761 },
3762 {
3763 IP: "3.4.5.6",
3764 Hostname: "test.cluster.com",
3765 },
3766 },
3767 },
3768 },
3769 },
3770 options: printers.GenerateOptions{},
3771
3772 expected: []metav1.TableRow{{Cells: []interface{}{"test6", "LoadBalancer", "10.9.8.7", "2.3.4.5,3.4.5.6,80.11.12.10,80.11.12.11", "8888/tcp", "<unknown>"}}},
3773 },
3774 {
3775
3776 service: api.Service{
3777 ObjectMeta: metav1.ObjectMeta{Name: "test7"},
3778 Spec: api.ServiceSpec{
3779 Type: api.ServiceTypeExternalName,
3780 ExternalName: "my.database.example.com",
3781 },
3782 },
3783 options: printers.GenerateOptions{},
3784
3785 expected: []metav1.TableRow{{Cells: []interface{}{"test7", "ExternalName", "<none>", "my.database.example.com", "<none>", "<unknown>"}}},
3786 },
3787 }
3788
3789 for i, test := range tests {
3790 rows, err := printService(&test.service, test.options)
3791 if err != nil {
3792 t.Fatal(err)
3793 }
3794 for i := range rows {
3795 rows[i].Object.Object = nil
3796 }
3797 if !reflect.DeepEqual(test.expected, rows) {
3798 t.Errorf("%d mismatch: %s", i, cmp.Diff(test.expected, rows))
3799 }
3800 }
3801 }
3802
3803 func TestPrintServiceList(t *testing.T) {
3804 serviceList := api.ServiceList{
3805 Items: []api.Service{
3806 {
3807 ObjectMeta: metav1.ObjectMeta{Name: "service1"},
3808 Spec: api.ServiceSpec{
3809 Type: api.ServiceTypeClusterIP,
3810 Ports: []api.ServicePort{
3811 {
3812 Protocol: "tcp",
3813 Port: 2233,
3814 },
3815 },
3816 ClusterIPs: []string{"10.9.8.7"},
3817 },
3818 },
3819 {
3820 ObjectMeta: metav1.ObjectMeta{Name: "service2"},
3821 Spec: api.ServiceSpec{
3822 Type: api.ServiceTypeNodePort,
3823 Ports: []api.ServicePort{
3824 {
3825 Protocol: "udp",
3826 Port: 5566,
3827 },
3828 },
3829 ClusterIPs: []string{"1.2.3.4"},
3830 },
3831 },
3832 },
3833 }
3834
3835
3836 expectedRows := []metav1.TableRow{
3837 {Cells: []interface{}{"service1", "ClusterIP", "10.9.8.7", "<none>", "2233/tcp", "<unknown>"}},
3838 {Cells: []interface{}{"service2", "NodePort", "1.2.3.4", "<none>", "5566/udp", "<unknown>"}},
3839 }
3840
3841 rows, err := printServiceList(&serviceList, printers.GenerateOptions{})
3842 if err != nil {
3843 t.Fatalf("Error printing service list: %#v", err)
3844 }
3845 for i := range rows {
3846 rows[i].Object.Object = nil
3847 }
3848 if !reflect.DeepEqual(expectedRows, rows) {
3849 t.Errorf("mismatch: %s", cmp.Diff(expectedRows, rows))
3850 }
3851 }
3852
3853 func TestPrintPodDisruptionBudget(t *testing.T) {
3854 minAvailable := intstr.FromInt32(22)
3855 maxUnavailable := intstr.FromInt32(11)
3856 tests := []struct {
3857 pdb policy.PodDisruptionBudget
3858 expected []metav1.TableRow
3859 }{
3860
3861 {
3862 pdb: policy.PodDisruptionBudget{
3863 ObjectMeta: metav1.ObjectMeta{
3864 Namespace: "ns1",
3865 Name: "pdb1",
3866 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
3867 },
3868 Spec: policy.PodDisruptionBudgetSpec{
3869 MinAvailable: &minAvailable,
3870 },
3871 Status: policy.PodDisruptionBudgetStatus{
3872 DisruptionsAllowed: 5,
3873 },
3874 },
3875
3876 expected: []metav1.TableRow{{Cells: []interface{}{"pdb1", "22", "N/A", int64(5), "0s"}}},
3877 },
3878
3879 {
3880 pdb: policy.PodDisruptionBudget{
3881 ObjectMeta: metav1.ObjectMeta{
3882 Namespace: "ns2",
3883 Name: "pdb2",
3884 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
3885 },
3886 Spec: policy.PodDisruptionBudgetSpec{
3887 MaxUnavailable: &maxUnavailable,
3888 },
3889 Status: policy.PodDisruptionBudgetStatus{
3890 DisruptionsAllowed: 5,
3891 },
3892 },
3893
3894 expected: []metav1.TableRow{{Cells: []interface{}{"pdb2", "N/A", "11", int64(5), "0s"}}},
3895 }}
3896
3897 for i, test := range tests {
3898 rows, err := printPodDisruptionBudget(&test.pdb, printers.GenerateOptions{})
3899 if err != nil {
3900 t.Fatal(err)
3901 }
3902 for i := range rows {
3903 rows[i].Object.Object = nil
3904 }
3905 if !reflect.DeepEqual(test.expected, rows) {
3906 t.Errorf("%d mismatch: %s", i, cmp.Diff(test.expected, rows))
3907 }
3908 }
3909 }
3910
3911 func TestPrintPodDisruptionBudgetList(t *testing.T) {
3912 minAvailable := intstr.FromInt32(22)
3913 maxUnavailable := intstr.FromInt32(11)
3914
3915 pdbList := policy.PodDisruptionBudgetList{
3916 Items: []policy.PodDisruptionBudget{
3917 {
3918 ObjectMeta: metav1.ObjectMeta{
3919 Namespace: "ns1",
3920 Name: "pdb1",
3921 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
3922 },
3923 Spec: policy.PodDisruptionBudgetSpec{
3924 MaxUnavailable: &maxUnavailable,
3925 },
3926 Status: policy.PodDisruptionBudgetStatus{
3927 DisruptionsAllowed: 5,
3928 },
3929 },
3930 {
3931 ObjectMeta: metav1.ObjectMeta{
3932 Namespace: "ns2",
3933 Name: "pdb2",
3934 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
3935 },
3936 Spec: policy.PodDisruptionBudgetSpec{
3937 MinAvailable: &minAvailable,
3938 },
3939 Status: policy.PodDisruptionBudgetStatus{
3940 DisruptionsAllowed: 3,
3941 },
3942 },
3943 },
3944 }
3945
3946
3947 expectedRows := []metav1.TableRow{
3948 {Cells: []interface{}{"pdb1", "N/A", "11", int64(5), "0s"}},
3949 {Cells: []interface{}{"pdb2", "22", "N/A", int64(3), "0s"}},
3950 }
3951
3952 rows, err := printPodDisruptionBudgetList(&pdbList, printers.GenerateOptions{})
3953 if err != nil {
3954 t.Fatalf("Error printing pod template list: %#v", err)
3955 }
3956 for i := range rows {
3957 rows[i].Object.Object = nil
3958 }
3959 if !reflect.DeepEqual(expectedRows, rows) {
3960 t.Errorf("mismatch: %s", cmp.Diff(expectedRows, rows))
3961 }
3962 }
3963
3964 func TestPrintControllerRevision(t *testing.T) {
3965 tests := []struct {
3966 history apps.ControllerRevision
3967 expected []metav1.TableRow
3968 }{
3969 {
3970 history: apps.ControllerRevision{
3971 ObjectMeta: metav1.ObjectMeta{
3972 Name: "test1",
3973 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
3974 OwnerReferences: []metav1.OwnerReference{
3975 {
3976 Controller: boolP(true),
3977 APIVersion: "apps/v1",
3978 Kind: "DaemonSet",
3979 Name: "foo",
3980 },
3981 },
3982 },
3983 Revision: 1,
3984 },
3985 expected: []metav1.TableRow{{Cells: []interface{}{"test1", "daemonset.apps/foo", int64(1), "0s"}}},
3986 },
3987 {
3988 history: apps.ControllerRevision{
3989 ObjectMeta: metav1.ObjectMeta{
3990 Name: "test2",
3991 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
3992 OwnerReferences: []metav1.OwnerReference{
3993 {
3994 Controller: boolP(false),
3995 Kind: "ABC",
3996 Name: "foo",
3997 },
3998 },
3999 },
4000 Revision: 2,
4001 },
4002 expected: []metav1.TableRow{{Cells: []interface{}{"test2", "<none>", int64(2), "0s"}}},
4003 },
4004 {
4005 history: apps.ControllerRevision{
4006 ObjectMeta: metav1.ObjectMeta{
4007 Name: "test3",
4008 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
4009 OwnerReferences: []metav1.OwnerReference{},
4010 },
4011 Revision: 3,
4012 },
4013 expected: []metav1.TableRow{{Cells: []interface{}{"test3", "<none>", int64(3), "0s"}}},
4014 },
4015 {
4016 history: apps.ControllerRevision{
4017 ObjectMeta: metav1.ObjectMeta{
4018 Name: "test4",
4019 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
4020 OwnerReferences: nil,
4021 },
4022 Revision: 4,
4023 },
4024 expected: []metav1.TableRow{{Cells: []interface{}{"test4", "<none>", int64(4), "0s"}}},
4025 },
4026 }
4027
4028 for i, test := range tests {
4029 rows, err := printControllerRevision(&test.history, printers.GenerateOptions{})
4030 if err != nil {
4031 t.Fatal(err)
4032 }
4033 for i := range rows {
4034 rows[i].Object.Object = nil
4035 }
4036 if !reflect.DeepEqual(test.expected, rows) {
4037 t.Errorf("%d mismatch: %s", i, cmp.Diff(test.expected, rows))
4038 }
4039 }
4040 }
4041
4042 func boolP(b bool) *bool {
4043 return &b
4044 }
4045
4046 func TestPrintConfigMap(t *testing.T) {
4047 tests := []struct {
4048 configMap api.ConfigMap
4049 expected []metav1.TableRow
4050 }{
4051
4052 {
4053 configMap: api.ConfigMap{
4054 ObjectMeta: metav1.ObjectMeta{
4055 Name: "configmap1",
4056 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
4057 },
4058 },
4059
4060 expected: []metav1.TableRow{{Cells: []interface{}{"configmap1", int64(0), "0s"}}},
4061 },
4062
4063 {
4064 configMap: api.ConfigMap{
4065 ObjectMeta: metav1.ObjectMeta{
4066 Name: "configmap2",
4067 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
4068 },
4069 Data: map[string]string{
4070 "foo": "bar",
4071 },
4072 },
4073
4074 expected: []metav1.TableRow{{Cells: []interface{}{"configmap2", int64(1), "0s"}}},
4075 },
4076
4077 {
4078 configMap: api.ConfigMap{
4079 ObjectMeta: metav1.ObjectMeta{
4080 Name: "configmap3",
4081 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
4082 },
4083 Data: map[string]string{
4084 "foo": "bar",
4085 },
4086 BinaryData: map[string][]byte{
4087 "bin": []byte("binary data"),
4088 },
4089 },
4090
4091 expected: []metav1.TableRow{{Cells: []interface{}{"configmap3", int64(2), "0s"}}},
4092 },
4093 }
4094
4095 for i, test := range tests {
4096 rows, err := printConfigMap(&test.configMap, printers.GenerateOptions{})
4097 if err != nil {
4098 t.Fatal(err)
4099 }
4100 for i := range rows {
4101 rows[i].Object.Object = nil
4102 }
4103 if !reflect.DeepEqual(test.expected, rows) {
4104 t.Errorf("%d mismatch: %s", i, cmp.Diff(test.expected, rows))
4105 }
4106 }
4107 }
4108
4109 func TestPrintNetworkPolicy(t *testing.T) {
4110 tests := []struct {
4111 policy networking.NetworkPolicy
4112 expected []metav1.TableRow
4113 }{
4114
4115 {
4116 policy: networking.NetworkPolicy{
4117 ObjectMeta: metav1.ObjectMeta{
4118 Name: "policy1",
4119 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
4120 },
4121 Spec: networking.NetworkPolicySpec{},
4122 },
4123
4124 expected: []metav1.TableRow{{Cells: []interface{}{"policy1", "<none>", "0s"}}},
4125 },
4126
4127 {
4128 policy: networking.NetworkPolicy{
4129 ObjectMeta: metav1.ObjectMeta{
4130 Name: "policy2",
4131 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
4132 },
4133 Spec: networking.NetworkPolicySpec{
4134 PodSelector: metav1.LabelSelector{MatchLabels: map[string]string{"foo": "bar"}},
4135 },
4136 },
4137
4138 expected: []metav1.TableRow{{Cells: []interface{}{"policy2", "foo=bar", "0s"}}},
4139 },
4140 }
4141
4142 for i, test := range tests {
4143 rows, err := printNetworkPolicy(&test.policy, printers.GenerateOptions{})
4144 if err != nil {
4145 t.Fatal(err)
4146 }
4147 for i := range rows {
4148 rows[i].Object.Object = nil
4149 }
4150 if !reflect.DeepEqual(test.expected, rows) {
4151 t.Errorf("%d mismatch: %s", i, cmp.Diff(test.expected, rows))
4152 }
4153 }
4154 }
4155
4156 func TestPrintRoleBinding(t *testing.T) {
4157 tests := []struct {
4158 binding rbac.RoleBinding
4159 options printers.GenerateOptions
4160 expected []metav1.TableRow
4161 }{
4162
4163 {
4164 binding: rbac.RoleBinding{
4165 ObjectMeta: metav1.ObjectMeta{
4166 Name: "binding1",
4167 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
4168 },
4169 Subjects: []rbac.Subject{
4170 {
4171 Kind: "User",
4172 Name: "system:kube-controller-manager",
4173 },
4174 },
4175 RoleRef: rbac.RoleRef{
4176 Kind: "Role",
4177 Name: "extension-apiserver-authentication-reader",
4178 },
4179 },
4180 options: printers.GenerateOptions{},
4181
4182 expected: []metav1.TableRow{{Cells: []interface{}{"binding1", "Role/extension-apiserver-authentication-reader", "0s"}}},
4183 },
4184
4185 {
4186 binding: rbac.RoleBinding{
4187 ObjectMeta: metav1.ObjectMeta{
4188 Name: "binding2",
4189 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
4190 },
4191 Subjects: []rbac.Subject{
4192 {
4193 Kind: "User",
4194 Name: "user-name",
4195 },
4196 {
4197 Kind: "Group",
4198 Name: "group-name",
4199 },
4200 {
4201 Kind: "ServiceAccount",
4202 Name: "service-account-name",
4203 Namespace: "service-account-namespace",
4204 },
4205 },
4206 RoleRef: rbac.RoleRef{
4207 Kind: "Role",
4208 Name: "role-name",
4209 },
4210 },
4211 options: printers.GenerateOptions{Wide: true},
4212
4213 expected: []metav1.TableRow{{Cells: []interface{}{"binding2", "Role/role-name", "0s", "user-name", "group-name", "service-account-namespace/service-account-name"}}},
4214 },
4215 }
4216
4217 for i, test := range tests {
4218 rows, err := printRoleBinding(&test.binding, test.options)
4219 if err != nil {
4220 t.Fatal(err)
4221 }
4222 for i := range rows {
4223 rows[i].Object.Object = nil
4224 }
4225 if !reflect.DeepEqual(test.expected, rows) {
4226 t.Errorf("%d mismatch: %s", i, cmp.Diff(test.expected, rows))
4227 }
4228 }
4229 }
4230
4231 func TestPrintClusterRoleBinding(t *testing.T) {
4232 tests := []struct {
4233 binding rbac.ClusterRoleBinding
4234 options printers.GenerateOptions
4235 expected []metav1.TableRow
4236 }{
4237
4238 {
4239 binding: rbac.ClusterRoleBinding{
4240 ObjectMeta: metav1.ObjectMeta{
4241 Name: "binding1",
4242 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
4243 },
4244 Subjects: []rbac.Subject{
4245 {
4246 Kind: "User",
4247 Name: "system:kube-controller-manager",
4248 },
4249 },
4250 RoleRef: rbac.RoleRef{
4251 Kind: "Role",
4252 Name: "extension-apiserver-authentication-reader",
4253 },
4254 },
4255 options: printers.GenerateOptions{},
4256
4257 expected: []metav1.TableRow{{Cells: []interface{}{"binding1", "Role/extension-apiserver-authentication-reader", "0s"}}},
4258 },
4259
4260 {
4261 binding: rbac.ClusterRoleBinding{
4262 ObjectMeta: metav1.ObjectMeta{
4263 Name: "binding2",
4264 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
4265 },
4266 Subjects: []rbac.Subject{
4267 {
4268 Kind: "User",
4269 Name: "user-name",
4270 },
4271 {
4272 Kind: "Group",
4273 Name: "group-name",
4274 },
4275 {
4276 Kind: "ServiceAccount",
4277 Name: "service-account-name",
4278 Namespace: "service-account-namespace",
4279 },
4280 },
4281 RoleRef: rbac.RoleRef{
4282 Kind: "Role",
4283 Name: "role-name",
4284 },
4285 },
4286 options: printers.GenerateOptions{Wide: true},
4287
4288 expected: []metav1.TableRow{{Cells: []interface{}{"binding2", "Role/role-name", "0s", "user-name", "group-name", "service-account-namespace/service-account-name"}}},
4289 },
4290 }
4291
4292 for i, test := range tests {
4293 rows, err := printClusterRoleBinding(&test.binding, test.options)
4294 if err != nil {
4295 t.Fatal(err)
4296 }
4297 for i := range rows {
4298 rows[i].Object.Object = nil
4299 }
4300 if !reflect.DeepEqual(test.expected, rows) {
4301 t.Errorf("%d mismatch: %s", i, cmp.Diff(test.expected, rows))
4302 }
4303 }
4304 }
4305 func TestPrintCertificateSigningRequest(t *testing.T) {
4306 tests := []struct {
4307 csr certificates.CertificateSigningRequest
4308 expected []metav1.TableRow
4309 }{
4310
4311 {
4312 csr: certificates.CertificateSigningRequest{
4313 ObjectMeta: metav1.ObjectMeta{
4314 Name: "csr1",
4315 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
4316 },
4317 Spec: certificates.CertificateSigningRequestSpec{},
4318 Status: certificates.CertificateSigningRequestStatus{},
4319 },
4320
4321 expected: []metav1.TableRow{{Cells: []interface{}{"csr1", "0s", "<none>", "", "<none>", "Pending"}}},
4322 },
4323
4324 {
4325 csr: certificates.CertificateSigningRequest{
4326 ObjectMeta: metav1.ObjectMeta{
4327 Name: "csr2",
4328 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
4329 },
4330 Spec: certificates.CertificateSigningRequestSpec{
4331 Username: "CSR Requestor",
4332 },
4333 Status: certificates.CertificateSigningRequestStatus{
4334 Conditions: []certificates.CertificateSigningRequestCondition{
4335 {
4336 Type: certificates.CertificateApproved,
4337 },
4338 },
4339 },
4340 },
4341
4342 expected: []metav1.TableRow{{Cells: []interface{}{"csr2", "0s", "<none>", "CSR Requestor", "<none>", "Approved"}}},
4343 },
4344
4345 {
4346 csr: certificates.CertificateSigningRequest{
4347 ObjectMeta: metav1.ObjectMeta{
4348 Name: "csr2",
4349 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
4350 },
4351 Spec: certificates.CertificateSigningRequestSpec{
4352 Username: "CSR Requestor",
4353 SignerName: "example.com/test-signer",
4354 },
4355 Status: certificates.CertificateSigningRequestStatus{
4356 Conditions: []certificates.CertificateSigningRequestCondition{
4357 {
4358 Type: certificates.CertificateApproved,
4359 },
4360 },
4361 },
4362 },
4363
4364 expected: []metav1.TableRow{{Cells: []interface{}{"csr2", "0s", "example.com/test-signer", "CSR Requestor", "<none>", "Approved"}}},
4365 },
4366
4367 {
4368 csr: certificates.CertificateSigningRequest{
4369 ObjectMeta: metav1.ObjectMeta{
4370 Name: "csr2",
4371 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
4372 },
4373 Spec: certificates.CertificateSigningRequestSpec{
4374 Username: "CSR Requestor",
4375 SignerName: "example.com/test-signer",
4376 ExpirationSeconds: csr.DurationToExpirationSeconds(7*24*time.Hour + time.Hour),
4377 },
4378 Status: certificates.CertificateSigningRequestStatus{
4379 Conditions: []certificates.CertificateSigningRequestCondition{
4380 {
4381 Type: certificates.CertificateApproved,
4382 },
4383 },
4384 },
4385 },
4386
4387 expected: []metav1.TableRow{{Cells: []interface{}{"csr2", "0s", "example.com/test-signer", "CSR Requestor", "7d1h", "Approved"}}},
4388 },
4389
4390 {
4391 csr: certificates.CertificateSigningRequest{
4392 ObjectMeta: metav1.ObjectMeta{
4393 Name: "csr2",
4394 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
4395 },
4396 Spec: certificates.CertificateSigningRequestSpec{
4397 Username: "CSR Requestor",
4398 },
4399 Status: certificates.CertificateSigningRequestStatus{
4400 Conditions: []certificates.CertificateSigningRequestCondition{
4401 {
4402 Type: certificates.CertificateApproved,
4403 },
4404 },
4405 Certificate: []byte("cert data"),
4406 },
4407 },
4408
4409 expected: []metav1.TableRow{{Cells: []interface{}{"csr2", "0s", "<none>", "CSR Requestor", "<none>", "Approved,Issued"}}},
4410 },
4411
4412 {
4413 csr: certificates.CertificateSigningRequest{
4414 ObjectMeta: metav1.ObjectMeta{
4415 Name: "csr3",
4416 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
4417 },
4418 Spec: certificates.CertificateSigningRequestSpec{
4419 Username: "CSR Requestor",
4420 },
4421 Status: certificates.CertificateSigningRequestStatus{
4422 Conditions: []certificates.CertificateSigningRequestCondition{
4423 {
4424 Type: certificates.CertificateDenied,
4425 },
4426 },
4427 },
4428 },
4429
4430 expected: []metav1.TableRow{{Cells: []interface{}{"csr3", "0s", "<none>", "CSR Requestor", "<none>", "Denied"}}},
4431 },
4432 }
4433
4434 for i, test := range tests {
4435 rows, err := printCertificateSigningRequest(&test.csr, printers.GenerateOptions{})
4436 if err != nil {
4437 t.Fatal(err)
4438 }
4439 for i := range rows {
4440 rows[i].Object.Object = nil
4441 }
4442 if !reflect.DeepEqual(test.expected, rows) {
4443 t.Errorf("%d mismatch: %s", i, cmp.Diff(test.expected, rows))
4444 }
4445 }
4446 }
4447
4448 func TestPrintReplicationController(t *testing.T) {
4449 tests := []struct {
4450 rc api.ReplicationController
4451 options printers.GenerateOptions
4452 expected []metav1.TableRow
4453 }{
4454
4455 {
4456 rc: api.ReplicationController{
4457 ObjectMeta: metav1.ObjectMeta{
4458 Name: "rc1",
4459 Namespace: "test-namespace",
4460 },
4461 Spec: api.ReplicationControllerSpec{
4462 Selector: map[string]string{"a": "b"},
4463 Template: &api.PodTemplateSpec{
4464 ObjectMeta: metav1.ObjectMeta{
4465 Labels: map[string]string{"a": "b"},
4466 },
4467 Spec: api.PodSpec{
4468 Containers: []api.Container{
4469 {
4470 Name: "test",
4471 Image: "test_image",
4472 ImagePullPolicy: api.PullIfNotPresent,
4473 TerminationMessagePolicy: api.TerminationMessageReadFile,
4474 },
4475 },
4476 RestartPolicy: api.RestartPolicyAlways,
4477 DNSPolicy: api.DNSClusterFirst,
4478 },
4479 },
4480 },
4481 },
4482 options: printers.GenerateOptions{},
4483
4484 expected: []metav1.TableRow{{Cells: []interface{}{"rc1", int64(0), int64(0), int64(0), "<unknown>"}}},
4485 },
4486
4487 {
4488 rc: api.ReplicationController{
4489 ObjectMeta: metav1.ObjectMeta{
4490 Name: "rc1",
4491 Namespace: "test-namespace",
4492 },
4493 Spec: api.ReplicationControllerSpec{
4494 Replicas: 5,
4495 Selector: map[string]string{"a": "b"},
4496 Template: &api.PodTemplateSpec{
4497 ObjectMeta: metav1.ObjectMeta{
4498 Labels: map[string]string{"a": "b"},
4499 },
4500 Spec: api.PodSpec{
4501 Containers: []api.Container{
4502 {
4503 Name: "test",
4504 Image: "test_image",
4505 ImagePullPolicy: api.PullIfNotPresent,
4506 TerminationMessagePolicy: api.TerminationMessageReadFile,
4507 },
4508 },
4509 RestartPolicy: api.RestartPolicyAlways,
4510 DNSPolicy: api.DNSClusterFirst,
4511 },
4512 },
4513 },
4514 Status: api.ReplicationControllerStatus{
4515 Replicas: 3,
4516 ReadyReplicas: 1,
4517 },
4518 },
4519 options: printers.GenerateOptions{},
4520
4521 expected: []metav1.TableRow{{Cells: []interface{}{"rc1", int64(5), int64(3), int64(1), "<unknown>"}}},
4522 },
4523
4524 {
4525 rc: api.ReplicationController{
4526 ObjectMeta: metav1.ObjectMeta{
4527 Name: "rc1",
4528 },
4529 Spec: api.ReplicationControllerSpec{
4530 Replicas: 5,
4531 Selector: map[string]string{"a": "b"},
4532 Template: &api.PodTemplateSpec{
4533 ObjectMeta: metav1.ObjectMeta{
4534 Labels: map[string]string{"a": "b"},
4535 },
4536 Spec: api.PodSpec{
4537 Containers: []api.Container{
4538 {
4539 Name: "test",
4540 Image: "test_image",
4541 ImagePullPolicy: api.PullIfNotPresent,
4542 TerminationMessagePolicy: api.TerminationMessageReadFile,
4543 },
4544 },
4545 RestartPolicy: api.RestartPolicyAlways,
4546 DNSPolicy: api.DNSClusterFirst,
4547 },
4548 },
4549 },
4550 Status: api.ReplicationControllerStatus{
4551 Replicas: 3,
4552 ReadyReplicas: 1,
4553 },
4554 },
4555 options: printers.GenerateOptions{Wide: true},
4556
4557 expected: []metav1.TableRow{{Cells: []interface{}{"rc1", int64(5), int64(3), int64(1), "<unknown>", "test", "test_image", "a=b"}}},
4558 },
4559 }
4560
4561 for i, test := range tests {
4562 rows, err := printReplicationController(&test.rc, test.options)
4563 if err != nil {
4564 t.Fatal(err)
4565 }
4566 for i := range rows {
4567 rows[i].Object.Object = nil
4568 }
4569 if !reflect.DeepEqual(test.expected, rows) {
4570 t.Errorf("%d mismatch: %s", i, cmp.Diff(test.expected, rows))
4571 }
4572 }
4573 }
4574
4575 func TestPrintReplicaSet(t *testing.T) {
4576 tests := []struct {
4577 replicaSet apps.ReplicaSet
4578 options printers.GenerateOptions
4579 expected []metav1.TableRow
4580 }{
4581
4582 {
4583 replicaSet: apps.ReplicaSet{
4584 ObjectMeta: metav1.ObjectMeta{
4585 Name: "test1",
4586 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
4587 },
4588 Spec: apps.ReplicaSetSpec{
4589 Replicas: 5,
4590 Template: api.PodTemplateSpec{
4591 Spec: api.PodSpec{
4592 Containers: []api.Container{
4593 {
4594 Name: "fake-container1",
4595 Image: "fake-image1",
4596 },
4597 {
4598 Name: "fake-container2",
4599 Image: "fake-image2",
4600 },
4601 },
4602 },
4603 },
4604 Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"foo": "bar"}},
4605 },
4606 Status: apps.ReplicaSetStatus{
4607 Replicas: 5,
4608 ReadyReplicas: 2,
4609 },
4610 },
4611 options: printers.GenerateOptions{},
4612
4613 expected: []metav1.TableRow{{Cells: []interface{}{"test1", int64(5), int64(5), int64(2), "0s"}}},
4614 },
4615
4616 {
4617 replicaSet: apps.ReplicaSet{
4618 ObjectMeta: metav1.ObjectMeta{
4619 Name: "test1",
4620 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
4621 },
4622 Spec: apps.ReplicaSetSpec{
4623 Replicas: 5,
4624 Template: api.PodTemplateSpec{
4625 Spec: api.PodSpec{
4626 Containers: []api.Container{
4627 {
4628 Name: "fake-container1",
4629 Image: "fake-image1",
4630 },
4631 {
4632 Name: "fake-container2",
4633 Image: "fake-image2",
4634 },
4635 },
4636 },
4637 },
4638 Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"foo": "bar"}},
4639 },
4640 Status: apps.ReplicaSetStatus{
4641 Replicas: 5,
4642 ReadyReplicas: 2,
4643 },
4644 },
4645 options: printers.GenerateOptions{Wide: true},
4646
4647 expected: []metav1.TableRow{{Cells: []interface{}{"test1", int64(5), int64(5), int64(2), "0s", "fake-container1,fake-container2", "fake-image1,fake-image2", "foo=bar"}}},
4648 },
4649 }
4650
4651 for i, test := range tests {
4652 rows, err := printReplicaSet(&test.replicaSet, test.options)
4653 if err != nil {
4654 t.Fatal(err)
4655 }
4656 for i := range rows {
4657 rows[i].Object.Object = nil
4658 }
4659 if !reflect.DeepEqual(test.expected, rows) {
4660 t.Errorf("%d mismatch: %s", i, cmp.Diff(test.expected, rows))
4661 }
4662 }
4663 }
4664
4665 func TestPrintReplicaSetList(t *testing.T) {
4666
4667 replicaSetList := apps.ReplicaSetList{
4668 Items: []apps.ReplicaSet{
4669 {
4670 ObjectMeta: metav1.ObjectMeta{
4671 Name: "replicaset1",
4672 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
4673 },
4674 Spec: apps.ReplicaSetSpec{
4675 Replicas: 5,
4676 Template: api.PodTemplateSpec{
4677 Spec: api.PodSpec{
4678 Containers: []api.Container{
4679 {
4680 Name: "fake-container1",
4681 Image: "fake-image1",
4682 },
4683 {
4684 Name: "fake-container2",
4685 Image: "fake-image2",
4686 },
4687 },
4688 },
4689 },
4690 },
4691 Status: apps.ReplicaSetStatus{
4692 Replicas: 5,
4693 ReadyReplicas: 2,
4694 },
4695 },
4696 {
4697 ObjectMeta: metav1.ObjectMeta{
4698 Name: "replicaset2",
4699 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
4700 },
4701 Spec: apps.ReplicaSetSpec{
4702 Replicas: 4,
4703 Template: api.PodTemplateSpec{},
4704 Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"foo": "bar"}},
4705 },
4706 Status: apps.ReplicaSetStatus{
4707 Replicas: 3,
4708 ReadyReplicas: 1,
4709 },
4710 },
4711 },
4712 }
4713
4714
4715 expectedRows := []metav1.TableRow{
4716 {Cells: []interface{}{"replicaset1", int64(5), int64(5), int64(2), "0s"}},
4717 {Cells: []interface{}{"replicaset2", int64(4), int64(3), int64(1), "0s"}},
4718 }
4719
4720 rows, err := printReplicaSetList(&replicaSetList, printers.GenerateOptions{})
4721 if err != nil {
4722 t.Fatalf("Error printing replica set list: %#v", err)
4723 }
4724 for i := range rows {
4725 rows[i].Object.Object = nil
4726 }
4727 if !reflect.DeepEqual(expectedRows, rows) {
4728 t.Errorf("mismatch: %s", cmp.Diff(expectedRows, rows))
4729 }
4730 }
4731
4732 func TestPrintStatefulSet(t *testing.T) {
4733 tests := []struct {
4734 statefulSet apps.StatefulSet
4735 options printers.GenerateOptions
4736 expected []metav1.TableRow
4737 }{
4738
4739 {
4740 statefulSet: apps.StatefulSet{
4741 ObjectMeta: metav1.ObjectMeta{
4742 Name: "test1",
4743 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
4744 },
4745 Spec: apps.StatefulSetSpec{
4746 Replicas: 5,
4747 Template: api.PodTemplateSpec{
4748 Spec: api.PodSpec{
4749 Containers: []api.Container{
4750 {
4751 Name: "fake-container1",
4752 Image: "fake-image1",
4753 },
4754 {
4755 Name: "fake-container2",
4756 Image: "fake-image2",
4757 },
4758 },
4759 },
4760 },
4761 },
4762 Status: apps.StatefulSetStatus{
4763 Replicas: 5,
4764 ReadyReplicas: 2,
4765 },
4766 },
4767 options: printers.GenerateOptions{},
4768
4769 expected: []metav1.TableRow{{Cells: []interface{}{"test1", "2/5", "0s"}}},
4770 },
4771
4772 {
4773 statefulSet: apps.StatefulSet{
4774 ObjectMeta: metav1.ObjectMeta{
4775 Name: "test1",
4776 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
4777 },
4778 Spec: apps.StatefulSetSpec{
4779 Replicas: 5,
4780 Template: api.PodTemplateSpec{
4781 Spec: api.PodSpec{
4782 Containers: []api.Container{
4783 {
4784 Name: "fake-container1",
4785 Image: "fake-image1",
4786 },
4787 {
4788 Name: "fake-container2",
4789 Image: "fake-image2",
4790 },
4791 },
4792 },
4793 },
4794 },
4795 Status: apps.StatefulSetStatus{
4796 Replicas: 5,
4797 ReadyReplicas: 2,
4798 },
4799 },
4800 options: printers.GenerateOptions{Wide: true},
4801
4802 expected: []metav1.TableRow{{Cells: []interface{}{"test1", "2/5", "0s", "fake-container1,fake-container2", "fake-image1,fake-image2"}}},
4803 },
4804 }
4805
4806 for i, test := range tests {
4807 rows, err := printStatefulSet(&test.statefulSet, test.options)
4808 if err != nil {
4809 t.Fatal(err)
4810 }
4811 for i := range rows {
4812 rows[i].Object.Object = nil
4813 }
4814 if !reflect.DeepEqual(test.expected, rows) {
4815 t.Errorf("%d mismatch: %s", i, cmp.Diff(test.expected, rows))
4816 }
4817 }
4818 }
4819
4820 func TestPrintPersistentVolume(t *testing.T) {
4821 myScn := "my-scn"
4822 myVacn := "my-vacn"
4823
4824 claimRef := api.ObjectReference{
4825 Name: "test",
4826 Namespace: "default",
4827 }
4828 tests := []struct {
4829 pv api.PersistentVolume
4830 expected []metav1.TableRow
4831 }{
4832 {
4833
4834 pv: api.PersistentVolume{
4835 ObjectMeta: metav1.ObjectMeta{
4836 Name: "test1",
4837 },
4838 Spec: api.PersistentVolumeSpec{
4839 ClaimRef: &claimRef,
4840 AccessModes: []api.PersistentVolumeAccessMode{api.ReadOnlyMany},
4841 Capacity: map[api.ResourceName]resource.Quantity{
4842 api.ResourceStorage: resource.MustParse("4Gi"),
4843 },
4844 },
4845 Status: api.PersistentVolumeStatus{
4846 Phase: api.VolumeBound,
4847 },
4848 },
4849 expected: []metav1.TableRow{{Cells: []interface{}{"test1", "4Gi", "ROX", "", "Bound", "default/test", "", "<unset>", "", "<unknown>", "<unset>"}}},
4850 },
4851 {
4852
4853 pv: api.PersistentVolume{
4854 ObjectMeta: metav1.ObjectMeta{
4855 Name: "test2",
4856 },
4857 Spec: api.PersistentVolumeSpec{
4858 ClaimRef: &claimRef,
4859 AccessModes: []api.PersistentVolumeAccessMode{api.ReadOnlyMany},
4860 Capacity: map[api.ResourceName]resource.Quantity{
4861 api.ResourceStorage: resource.MustParse("4Gi"),
4862 },
4863 },
4864 Status: api.PersistentVolumeStatus{
4865 Phase: api.VolumeFailed,
4866 },
4867 },
4868 expected: []metav1.TableRow{{Cells: []interface{}{"test2", "4Gi", "ROX", "", "Failed", "default/test", "", "<unset>", "", "<unknown>", "<unset>"}}},
4869 },
4870 {
4871
4872 pv: api.PersistentVolume{
4873 ObjectMeta: metav1.ObjectMeta{
4874 Name: "test3",
4875 },
4876 Spec: api.PersistentVolumeSpec{
4877 ClaimRef: &claimRef,
4878 AccessModes: []api.PersistentVolumeAccessMode{api.ReadWriteMany},
4879 Capacity: map[api.ResourceName]resource.Quantity{
4880 api.ResourceStorage: resource.MustParse("10Gi"),
4881 },
4882 },
4883 Status: api.PersistentVolumeStatus{
4884 Phase: api.VolumePending,
4885 },
4886 },
4887 expected: []metav1.TableRow{{Cells: []interface{}{"test3", "10Gi", "RWX", "", "Pending", "default/test", "", "<unset>", "", "<unknown>", "<unset>"}}},
4888 },
4889 {
4890
4891 pv: api.PersistentVolume{
4892 ObjectMeta: metav1.ObjectMeta{
4893 Name: "test4",
4894 },
4895 Spec: api.PersistentVolumeSpec{
4896 ClaimRef: &claimRef,
4897 StorageClassName: myScn,
4898 AccessModes: []api.PersistentVolumeAccessMode{api.ReadWriteOnce},
4899 Capacity: map[api.ResourceName]resource.Quantity{
4900 api.ResourceStorage: resource.MustParse("10Gi"),
4901 },
4902 },
4903 Status: api.PersistentVolumeStatus{
4904 Phase: api.VolumePending,
4905 },
4906 },
4907 expected: []metav1.TableRow{{Cells: []interface{}{"test4", "10Gi", "RWO", "", "Pending", "default/test", "my-scn", "<unset>", "", "<unknown>", "<unset>"}}},
4908 },
4909 {
4910
4911 pv: api.PersistentVolume{
4912 ObjectMeta: metav1.ObjectMeta{
4913 Name: "test4",
4914 },
4915 Spec: api.PersistentVolumeSpec{
4916 ClaimRef: &claimRef,
4917 StorageClassName: myScn,
4918 VolumeAttributesClassName: &myVacn,
4919 AccessModes: []api.PersistentVolumeAccessMode{api.ReadWriteOnce},
4920 Capacity: map[api.ResourceName]resource.Quantity{
4921 api.ResourceStorage: resource.MustParse("10Gi"),
4922 },
4923 },
4924 Status: api.PersistentVolumeStatus{
4925 Phase: api.VolumePending,
4926 },
4927 },
4928 expected: []metav1.TableRow{{Cells: []interface{}{"test4", "10Gi", "RWO", "", "Pending", "default/test", "my-scn", "my-vacn", "", "<unknown>", "<unset>"}}},
4929 },
4930 {
4931
4932 pv: api.PersistentVolume{
4933 ObjectMeta: metav1.ObjectMeta{
4934 Name: "test5",
4935 },
4936 Spec: api.PersistentVolumeSpec{
4937 ClaimRef: &claimRef,
4938 StorageClassName: myScn,
4939 AccessModes: []api.PersistentVolumeAccessMode{api.ReadWriteOnce},
4940 Capacity: map[api.ResourceName]resource.Quantity{
4941 api.ResourceStorage: resource.MustParse("10Gi"),
4942 },
4943 },
4944 Status: api.PersistentVolumeStatus{
4945 Phase: api.VolumeAvailable,
4946 },
4947 },
4948 expected: []metav1.TableRow{{Cells: []interface{}{"test5", "10Gi", "RWO", "", "Available", "default/test", "my-scn", "<unset>", "", "<unknown>", "<unset>"}}},
4949 },
4950 {
4951
4952 pv: api.PersistentVolume{
4953 ObjectMeta: metav1.ObjectMeta{
4954 Name: "test6",
4955 },
4956 Spec: api.PersistentVolumeSpec{
4957 ClaimRef: &claimRef,
4958 StorageClassName: myScn,
4959 AccessModes: []api.PersistentVolumeAccessMode{api.ReadWriteOnce},
4960 Capacity: map[api.ResourceName]resource.Quantity{
4961 api.ResourceStorage: resource.MustParse("10Gi"),
4962 },
4963 },
4964 Status: api.PersistentVolumeStatus{
4965 Phase: api.VolumeReleased,
4966 },
4967 },
4968 expected: []metav1.TableRow{{Cells: []interface{}{"test6", "10Gi", "RWO", "", "Released", "default/test", "my-scn", "<unset>", "", "<unknown>", "<unset>"}}},
4969 },
4970 }
4971
4972 for i, test := range tests {
4973 rows, err := printPersistentVolume(&test.pv, printers.GenerateOptions{})
4974 if err != nil {
4975 t.Fatal(err)
4976 }
4977 for i := range rows {
4978 rows[i].Object.Object = nil
4979 }
4980 if !reflect.DeepEqual(test.expected, rows) {
4981 t.Errorf("%d mismatch: %s", i, cmp.Diff(test.expected, rows))
4982 }
4983 }
4984 }
4985
4986 func TestPrintPersistentVolumeClaim(t *testing.T) {
4987 volumeMode := api.PersistentVolumeFilesystem
4988 myVacn := "my-vacn"
4989 myScn := "my-scn"
4990 tests := []struct {
4991 pvc api.PersistentVolumeClaim
4992 expected []metav1.TableRow
4993 }{
4994 {
4995
4996 pvc: api.PersistentVolumeClaim{
4997 ObjectMeta: metav1.ObjectMeta{
4998 Name: "test1",
4999 },
5000 Spec: api.PersistentVolumeClaimSpec{
5001 VolumeName: "my-volume",
5002 VolumeMode: &volumeMode,
5003 },
5004 Status: api.PersistentVolumeClaimStatus{
5005 Phase: api.ClaimBound,
5006 AccessModes: []api.PersistentVolumeAccessMode{api.ReadOnlyMany},
5007 Capacity: map[api.ResourceName]resource.Quantity{
5008 api.ResourceStorage: resource.MustParse("4Gi"),
5009 },
5010 },
5011 },
5012 expected: []metav1.TableRow{{Cells: []interface{}{"test1", "Bound", "my-volume", "4Gi", "ROX", "", "<unset>", "<unknown>", "Filesystem"}}},
5013 },
5014 {
5015
5016 pvc: api.PersistentVolumeClaim{
5017 ObjectMeta: metav1.ObjectMeta{
5018 Name: "test2",
5019 },
5020 Spec: api.PersistentVolumeClaimSpec{
5021 VolumeMode: &volumeMode,
5022 },
5023 Status: api.PersistentVolumeClaimStatus{
5024 Phase: api.ClaimLost,
5025 AccessModes: []api.PersistentVolumeAccessMode{api.ReadOnlyMany},
5026 Capacity: map[api.ResourceName]resource.Quantity{
5027 api.ResourceStorage: resource.MustParse("4Gi"),
5028 },
5029 },
5030 },
5031 expected: []metav1.TableRow{{Cells: []interface{}{"test2", "Lost", "", "", "", "", "<unset>", "<unknown>", "Filesystem"}}},
5032 },
5033 {
5034
5035 pvc: api.PersistentVolumeClaim{
5036 ObjectMeta: metav1.ObjectMeta{
5037 Name: "test3",
5038 },
5039 Spec: api.PersistentVolumeClaimSpec{
5040 VolumeName: "my-volume",
5041 VolumeMode: &volumeMode,
5042 },
5043 Status: api.PersistentVolumeClaimStatus{
5044 Phase: api.ClaimPending,
5045 AccessModes: []api.PersistentVolumeAccessMode{api.ReadWriteMany},
5046 Capacity: map[api.ResourceName]resource.Quantity{
5047 api.ResourceStorage: resource.MustParse("10Gi"),
5048 },
5049 },
5050 },
5051 expected: []metav1.TableRow{{Cells: []interface{}{"test3", "Pending", "my-volume", "10Gi", "RWX", "", "<unset>", "<unknown>", "Filesystem"}}},
5052 },
5053 {
5054
5055 pvc: api.PersistentVolumeClaim{
5056 ObjectMeta: metav1.ObjectMeta{
5057 Name: "test4",
5058 },
5059 Spec: api.PersistentVolumeClaimSpec{
5060 VolumeName: "my-volume",
5061 StorageClassName: &myScn,
5062 VolumeMode: &volumeMode,
5063 },
5064 Status: api.PersistentVolumeClaimStatus{
5065 Phase: api.ClaimPending,
5066 AccessModes: []api.PersistentVolumeAccessMode{api.ReadWriteOnce},
5067 Capacity: map[api.ResourceName]resource.Quantity{
5068 api.ResourceStorage: resource.MustParse("10Gi"),
5069 },
5070 },
5071 },
5072 expected: []metav1.TableRow{{Cells: []interface{}{"test4", "Pending", "my-volume", "10Gi", "RWO", "my-scn", "<unset>", "<unknown>", "Filesystem"}}},
5073 },
5074 {
5075
5076 pvc: api.PersistentVolumeClaim{
5077 ObjectMeta: metav1.ObjectMeta{
5078 Name: "test5",
5079 },
5080 Spec: api.PersistentVolumeClaimSpec{
5081 VolumeName: "my-volume",
5082 StorageClassName: &myScn,
5083 },
5084 Status: api.PersistentVolumeClaimStatus{
5085 Phase: api.ClaimPending,
5086 AccessModes: []api.PersistentVolumeAccessMode{api.ReadWriteOnce},
5087 Capacity: map[api.ResourceName]resource.Quantity{
5088 api.ResourceStorage: resource.MustParse("10Gi"),
5089 },
5090 },
5091 },
5092 expected: []metav1.TableRow{{Cells: []interface{}{"test5", "Pending", "my-volume", "10Gi", "RWO", "my-scn", "<unset>", "<unknown>", "<unset>"}}},
5093 },
5094 {
5095
5096 pvc: api.PersistentVolumeClaim{
5097 ObjectMeta: metav1.ObjectMeta{
5098 Name: "test5",
5099 },
5100 Spec: api.PersistentVolumeClaimSpec{
5101 VolumeName: "my-volume",
5102 StorageClassName: &myScn,
5103 VolumeAttributesClassName: &myVacn,
5104 },
5105 Status: api.PersistentVolumeClaimStatus{
5106 Phase: api.ClaimPending,
5107 AccessModes: []api.PersistentVolumeAccessMode{api.ReadWriteOnce},
5108 Capacity: map[api.ResourceName]resource.Quantity{
5109 api.ResourceStorage: resource.MustParse("10Gi"),
5110 },
5111 },
5112 },
5113 expected: []metav1.TableRow{{Cells: []interface{}{"test5", "Pending", "my-volume", "10Gi", "RWO", "my-scn", "my-vacn", "<unknown>", "<unset>"}}},
5114 },
5115 }
5116
5117 for i, test := range tests {
5118 rows, err := printPersistentVolumeClaim(&test.pvc, printers.GenerateOptions{})
5119 if err != nil {
5120 t.Fatal(err)
5121 }
5122 for i := range rows {
5123 rows[i].Object.Object = nil
5124 }
5125 if !reflect.DeepEqual(test.expected, rows) {
5126 t.Errorf("%d mismatch: %s", i, cmp.Diff(test.expected, rows))
5127 }
5128 }
5129 }
5130
5131 func TestPrintComponentStatus(t *testing.T) {
5132 tests := []struct {
5133 componentStatus api.ComponentStatus
5134 expected []metav1.TableRow
5135 }{
5136
5137 {
5138 componentStatus: api.ComponentStatus{
5139 ObjectMeta: metav1.ObjectMeta{
5140 Name: "cs1",
5141 },
5142 Conditions: []api.ComponentCondition{},
5143 },
5144
5145 expected: []metav1.TableRow{{Cells: []interface{}{"cs1", "Unknown", "", ""}}},
5146 },
5147
5148 {
5149 componentStatus: api.ComponentStatus{
5150 ObjectMeta: metav1.ObjectMeta{
5151 Name: "cs2",
5152 },
5153 Conditions: []api.ComponentCondition{
5154 {
5155 Type: "Healthy",
5156 Status: api.ConditionTrue,
5157 Message: "test message",
5158 Error: "test error",
5159 },
5160 },
5161 },
5162
5163 expected: []metav1.TableRow{{Cells: []interface{}{"cs2", "Healthy", "test message", "test error"}}},
5164 },
5165
5166 {
5167 componentStatus: api.ComponentStatus{
5168 ObjectMeta: metav1.ObjectMeta{
5169 Name: "cs3",
5170 },
5171 Conditions: []api.ComponentCondition{
5172 {
5173 Type: "Healthy",
5174 Status: api.ConditionFalse,
5175 Message: "test message",
5176 Error: "test error",
5177 },
5178 },
5179 },
5180
5181 expected: []metav1.TableRow{{Cells: []interface{}{"cs3", "Unhealthy", "test message", "test error"}}},
5182 },
5183 }
5184
5185 for i, test := range tests {
5186 rows, err := printComponentStatus(&test.componentStatus, printers.GenerateOptions{})
5187 if err != nil {
5188 t.Fatal(err)
5189 }
5190 for i := range rows {
5191 rows[i].Object.Object = nil
5192 }
5193 if !reflect.DeepEqual(test.expected, rows) {
5194 t.Errorf("%d mismatch: %s", i, cmp.Diff(test.expected, rows))
5195 }
5196 }
5197 }
5198
5199 func TestPrintCronJob(t *testing.T) {
5200 timeZone := "LOCAL"
5201 completions := int32(2)
5202 suspend := false
5203 tests := []struct {
5204 cronjob batch.CronJob
5205 options printers.GenerateOptions
5206 expected []metav1.TableRow
5207 }{
5208
5209 {
5210 cronjob: batch.CronJob{
5211 ObjectMeta: metav1.ObjectMeta{
5212 Name: "cronjob1",
5213 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
5214 },
5215 Spec: batch.CronJobSpec{
5216 Schedule: "0/5 * * * ?",
5217 Suspend: &suspend,
5218 JobTemplate: batch.JobTemplateSpec{
5219 Spec: batch.JobSpec{
5220 Completions: &completions,
5221 Template: api.PodTemplateSpec{
5222 Spec: api.PodSpec{
5223 Containers: []api.Container{
5224 {
5225 Name: "fake-job-container1",
5226 Image: "fake-job-image1",
5227 },
5228 {
5229 Name: "fake-job-container2",
5230 Image: "fake-job-image2",
5231 },
5232 },
5233 },
5234 },
5235 Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"a": "b"}},
5236 },
5237 },
5238 },
5239 Status: batch.CronJobStatus{
5240 LastScheduleTime: &metav1.Time{Time: time.Now().Add(1.9e9)},
5241 },
5242 },
5243 options: printers.GenerateOptions{},
5244
5245 expected: []metav1.TableRow{{Cells: []interface{}{"cronjob1", "0/5 * * * ?", "<none>", "False", int64(0), "0s", "0s"}}},
5246 },
5247
5248 {
5249 cronjob: batch.CronJob{
5250 ObjectMeta: metav1.ObjectMeta{
5251 Name: "cronjob1",
5252 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
5253 },
5254 Spec: batch.CronJobSpec{
5255 Schedule: "0/5 * * * ?",
5256 TimeZone: &timeZone,
5257 Suspend: &suspend,
5258 JobTemplate: batch.JobTemplateSpec{
5259 Spec: batch.JobSpec{
5260 Completions: &completions,
5261 Template: api.PodTemplateSpec{
5262 Spec: api.PodSpec{
5263 Containers: []api.Container{
5264 {
5265 Name: "fake-job-container1",
5266 Image: "fake-job-image1",
5267 },
5268 {
5269 Name: "fake-job-container2",
5270 Image: "fake-job-image2",
5271 },
5272 },
5273 },
5274 },
5275 Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"a": "b"}},
5276 },
5277 },
5278 },
5279 Status: batch.CronJobStatus{
5280 LastScheduleTime: &metav1.Time{Time: time.Now().Add(1.9e9)},
5281 },
5282 },
5283 options: printers.GenerateOptions{},
5284
5285 expected: []metav1.TableRow{{Cells: []interface{}{"cronjob1", "0/5 * * * ?", "LOCAL", "False", int64(0), "0s", "0s"}}},
5286 },
5287
5288 {
5289 cronjob: batch.CronJob{
5290 ObjectMeta: metav1.ObjectMeta{
5291 Name: "cronjob1",
5292 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
5293 },
5294 Spec: batch.CronJobSpec{
5295 Schedule: "0/5 * * * ?",
5296 Suspend: &suspend,
5297 JobTemplate: batch.JobTemplateSpec{
5298 Spec: batch.JobSpec{
5299 Completions: &completions,
5300 Template: api.PodTemplateSpec{
5301 Spec: api.PodSpec{
5302 Containers: []api.Container{
5303 {
5304 Name: "fake-job-container1",
5305 Image: "fake-job-image1",
5306 },
5307 {
5308 Name: "fake-job-container2",
5309 Image: "fake-job-image2",
5310 },
5311 },
5312 },
5313 },
5314 Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"a": "b"}},
5315 },
5316 },
5317 },
5318 Status: batch.CronJobStatus{
5319 LastScheduleTime: &metav1.Time{Time: time.Now().Add(1.9e9)},
5320 },
5321 },
5322 options: printers.GenerateOptions{Wide: true},
5323
5324 expected: []metav1.TableRow{{Cells: []interface{}{"cronjob1", "0/5 * * * ?", "<none>", "False", int64(0), "0s", "0s", "fake-job-container1,fake-job-container2", "fake-job-image1,fake-job-image2", "a=b"}}},
5325 },
5326
5327 {
5328 cronjob: batch.CronJob{
5329 ObjectMeta: metav1.ObjectMeta{
5330 Name: "cronjob2",
5331 CreationTimestamp: metav1.Time{Time: time.Now().Add(-3e11)},
5332 },
5333 Spec: batch.CronJobSpec{
5334 Schedule: "0/5 * * * ?",
5335 Suspend: &suspend,
5336 },
5337 Status: batch.CronJobStatus{
5338 LastScheduleTime: &metav1.Time{Time: time.Now().Add(-3e10)},
5339 },
5340 },
5341 options: printers.GenerateOptions{},
5342
5343 expected: []metav1.TableRow{{Cells: []interface{}{"cronjob2", "0/5 * * * ?", "<none>", "False", int64(0), "30s", "5m"}}},
5344 },
5345
5346 {
5347 cronjob: batch.CronJob{
5348 ObjectMeta: metav1.ObjectMeta{
5349 Name: "cronjob3",
5350 CreationTimestamp: metav1.Time{Time: time.Now().Add(-3e11)},
5351 },
5352 Spec: batch.CronJobSpec{
5353 Schedule: "0/5 * * * ?",
5354 Suspend: &suspend,
5355 },
5356 Status: batch.CronJobStatus{},
5357 },
5358 options: printers.GenerateOptions{},
5359
5360 expected: []metav1.TableRow{{Cells: []interface{}{"cronjob3", "0/5 * * * ?", "<none>", "False", int64(0), "<none>", "5m"}}},
5361 },
5362 }
5363
5364 for i, test := range tests {
5365 rows, err := printCronJob(&test.cronjob, test.options)
5366 if err != nil {
5367 t.Fatal(err)
5368 }
5369 for i := range rows {
5370 rows[i].Object.Object = nil
5371 }
5372 if !reflect.DeepEqual(test.expected, rows) {
5373 t.Errorf("%d mismatch: %s", i, cmp.Diff(test.expected, rows))
5374 }
5375 }
5376 }
5377
5378 func TestPrintCronJobList(t *testing.T) {
5379 timeZone := "LOCAL"
5380 completions := int32(2)
5381 suspend := false
5382
5383 cronJobList := batch.CronJobList{
5384 Items: []batch.CronJob{
5385 {
5386 ObjectMeta: metav1.ObjectMeta{
5387 Name: "cronjob1",
5388 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
5389 },
5390 Spec: batch.CronJobSpec{
5391 Schedule: "0/5 * * * ?",
5392 TimeZone: &timeZone,
5393 Suspend: &suspend,
5394 JobTemplate: batch.JobTemplateSpec{
5395 Spec: batch.JobSpec{
5396 Completions: &completions,
5397 Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"a": "b"}},
5398 },
5399 },
5400 },
5401 Status: batch.CronJobStatus{
5402 LastScheduleTime: &metav1.Time{Time: time.Now().Add(1.9e9)},
5403 },
5404 },
5405 {
5406 ObjectMeta: metav1.ObjectMeta{
5407 Name: "cronjob2",
5408 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
5409 },
5410 Spec: batch.CronJobSpec{
5411 Schedule: "4/5 1 1 1 ?",
5412 Suspend: &suspend,
5413 JobTemplate: batch.JobTemplateSpec{
5414 Spec: batch.JobSpec{
5415 Completions: &completions,
5416 Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"a": "b"}},
5417 },
5418 },
5419 },
5420 Status: batch.CronJobStatus{
5421 LastScheduleTime: &metav1.Time{Time: time.Now().Add(-20 * time.Minute)},
5422 },
5423 },
5424 },
5425 }
5426
5427
5428 expectedRows := []metav1.TableRow{
5429 {Cells: []interface{}{"cronjob1", "0/5 * * * ?", "LOCAL", "False", int64(0), "0s", "0s"}},
5430 {Cells: []interface{}{"cronjob2", "4/5 1 1 1 ?", "<none>", "False", int64(0), "20m", "0s"}},
5431 }
5432
5433 rows, err := printCronJobList(&cronJobList, printers.GenerateOptions{})
5434 if err != nil {
5435 t.Fatalf("Error printing job list: %#v", err)
5436 }
5437 for i := range rows {
5438 rows[i].Object.Object = nil
5439 }
5440 if !reflect.DeepEqual(expectedRows, rows) {
5441 t.Errorf("mismatch: %s", cmp.Diff(expectedRows, rows))
5442 }
5443 }
5444
5445 func TestPrintStorageClass(t *testing.T) {
5446 policyDelte := api.PersistentVolumeReclaimDelete
5447 policyRetain := api.PersistentVolumeReclaimRetain
5448 bindModeImmediate := storage.VolumeBindingImmediate
5449 bindModeWait := storage.VolumeBindingWaitForFirstConsumer
5450 tests := []struct {
5451 sc storage.StorageClass
5452 expected []metav1.TableRow
5453 }{
5454 {
5455 sc: storage.StorageClass{
5456 ObjectMeta: metav1.ObjectMeta{
5457 Name: "sc1",
5458 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
5459 },
5460 Provisioner: "kubernetes.io/glusterfs",
5461 },
5462 expected: []metav1.TableRow{{Cells: []interface{}{"sc1", "kubernetes.io/glusterfs", "Delete",
5463 "Immediate", false, "0s"}}},
5464 },
5465 {
5466 sc: storage.StorageClass{
5467 ObjectMeta: metav1.ObjectMeta{
5468 Name: "sc2",
5469 CreationTimestamp: metav1.Time{Time: time.Now().Add(-3e11)},
5470 },
5471 Provisioner: "kubernetes.io/nfs",
5472 },
5473 expected: []metav1.TableRow{{Cells: []interface{}{"sc2", "kubernetes.io/nfs", "Delete",
5474 "Immediate", false, "5m"}}},
5475 },
5476 {
5477 sc: storage.StorageClass{
5478 ObjectMeta: metav1.ObjectMeta{
5479 Name: "sc3",
5480 CreationTimestamp: metav1.Time{Time: time.Now().Add(-3e11)},
5481 },
5482 Provisioner: "kubernetes.io/nfs",
5483 ReclaimPolicy: &policyDelte,
5484 },
5485 expected: []metav1.TableRow{{Cells: []interface{}{"sc3", "kubernetes.io/nfs", "Delete",
5486 "Immediate", false, "5m"}}},
5487 },
5488 {
5489 sc: storage.StorageClass{
5490 ObjectMeta: metav1.ObjectMeta{
5491 Name: "sc4",
5492 CreationTimestamp: metav1.Time{Time: time.Now().Add(-3e11)},
5493 },
5494 Provisioner: "kubernetes.io/nfs",
5495 ReclaimPolicy: &policyRetain,
5496 VolumeBindingMode: &bindModeImmediate,
5497 },
5498 expected: []metav1.TableRow{{Cells: []interface{}{"sc4", "kubernetes.io/nfs", "Retain",
5499 "Immediate", false, "5m"}}},
5500 },
5501 {
5502 sc: storage.StorageClass{
5503 ObjectMeta: metav1.ObjectMeta{
5504 Name: "sc5",
5505 CreationTimestamp: metav1.Time{Time: time.Now().Add(-3e11)},
5506 },
5507 Provisioner: "kubernetes.io/nfs",
5508 ReclaimPolicy: &policyRetain,
5509 VolumeBindingMode: &bindModeWait,
5510 },
5511 expected: []metav1.TableRow{{Cells: []interface{}{"sc5", "kubernetes.io/nfs", "Retain",
5512 "WaitForFirstConsumer", false, "5m"}}},
5513 },
5514 {
5515 sc: storage.StorageClass{
5516 ObjectMeta: metav1.ObjectMeta{
5517 Name: "sc6",
5518 CreationTimestamp: metav1.Time{Time: time.Now().Add(-3e11)},
5519 },
5520 Provisioner: "kubernetes.io/nfs",
5521 ReclaimPolicy: &policyRetain,
5522 AllowVolumeExpansion: boolP(true),
5523 VolumeBindingMode: &bindModeWait,
5524 },
5525 expected: []metav1.TableRow{{Cells: []interface{}{"sc6", "kubernetes.io/nfs", "Retain",
5526 "WaitForFirstConsumer", true, "5m"}}},
5527 },
5528 }
5529
5530 for i, test := range tests {
5531 rows, err := printStorageClass(&test.sc, printers.GenerateOptions{})
5532 if err != nil {
5533 t.Fatal(err)
5534 }
5535 for i := range rows {
5536 rows[i].Object.Object = nil
5537 }
5538 if !reflect.DeepEqual(test.expected, rows) {
5539 t.Errorf("%d mismatch: %s", i, cmp.Diff(test.expected, rows))
5540 }
5541 }
5542 }
5543
5544 func TestPrintVolumeAttributesClass(t *testing.T) {
5545 tests := []struct {
5546 vac storage.VolumeAttributesClass
5547 expected []metav1.TableRow
5548 }{
5549 {
5550 vac: storage.VolumeAttributesClass{
5551 ObjectMeta: metav1.ObjectMeta{
5552 Name: "vac1",
5553 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
5554 },
5555 DriverName: "fake",
5556 },
5557 expected: []metav1.TableRow{{Cells: []interface{}{"vac1", "fake", "0s"}}},
5558 },
5559 {
5560 vac: storage.VolumeAttributesClass{
5561 ObjectMeta: metav1.ObjectMeta{
5562 Name: "vac2",
5563 CreationTimestamp: metav1.Time{Time: time.Now().Add(-3e11)},
5564 },
5565 DriverName: "fake",
5566 Parameters: map[string]string{
5567 "iops": "500",
5568 "throughput": "50MiB/s",
5569 },
5570 },
5571 expected: []metav1.TableRow{{Cells: []interface{}{"vac2", "fake", "5m"}}},
5572 },
5573 }
5574
5575 for i, test := range tests {
5576 rows, err := printVolumeAttributesClass(&test.vac, printers.GenerateOptions{})
5577 if err != nil {
5578 t.Fatal(err)
5579 }
5580 for i := range rows {
5581 rows[i].Object.Object = nil
5582 }
5583 if !reflect.DeepEqual(test.expected, rows) {
5584 t.Errorf("%d mismatch: %s", i, cmp.Diff(test.expected, rows))
5585 }
5586 }
5587 }
5588
5589 func TestPrintLease(t *testing.T) {
5590 holder1 := "holder1"
5591 holder2 := "holder2"
5592 tests := []struct {
5593 lease coordination.Lease
5594 expected []metav1.TableRow
5595 }{
5596 {
5597 lease: coordination.Lease{
5598 ObjectMeta: metav1.ObjectMeta{
5599 Name: "lease1",
5600 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
5601 },
5602 Spec: coordination.LeaseSpec{
5603 HolderIdentity: &holder1,
5604 },
5605 },
5606 expected: []metav1.TableRow{{Cells: []interface{}{"lease1", "holder1", "0s"}}},
5607 },
5608 {
5609 lease: coordination.Lease{
5610 ObjectMeta: metav1.ObjectMeta{
5611 Name: "lease2",
5612 CreationTimestamp: metav1.Time{Time: time.Now().Add(-3e11)},
5613 },
5614 Spec: coordination.LeaseSpec{
5615 HolderIdentity: &holder2,
5616 },
5617 },
5618 expected: []metav1.TableRow{{Cells: []interface{}{"lease2", "holder2", "5m"}}},
5619 },
5620 }
5621
5622 for i, test := range tests {
5623 rows, err := printLease(&test.lease, printers.GenerateOptions{})
5624 if err != nil {
5625 t.Fatal(err)
5626 }
5627 for i := range rows {
5628 rows[i].Object.Object = nil
5629 }
5630 if !reflect.DeepEqual(test.expected, rows) {
5631 t.Errorf("%d mismatch: %s", i, cmp.Diff(test.expected, rows))
5632 }
5633 }
5634 }
5635
5636 func TestPrintPriorityClass(t *testing.T) {
5637 tests := []struct {
5638 pc scheduling.PriorityClass
5639 expected []metav1.TableRow
5640 }{
5641 {
5642 pc: scheduling.PriorityClass{
5643 ObjectMeta: metav1.ObjectMeta{
5644 Name: "pc1",
5645 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
5646 },
5647 Value: 1,
5648 },
5649 expected: []metav1.TableRow{{Cells: []interface{}{"pc1", int64(1), bool(false), "0s"}}},
5650 },
5651 {
5652 pc: scheduling.PriorityClass{
5653 ObjectMeta: metav1.ObjectMeta{
5654 Name: "pc2",
5655 CreationTimestamp: metav1.Time{Time: time.Now().Add(-3e11)},
5656 },
5657 Value: 1000000000,
5658 GlobalDefault: true,
5659 },
5660 expected: []metav1.TableRow{{Cells: []interface{}{"pc2", int64(1000000000), bool(true), "5m"}}},
5661 },
5662 }
5663
5664 for i, test := range tests {
5665 rows, err := printPriorityClass(&test.pc, printers.GenerateOptions{})
5666 if err != nil {
5667 t.Fatal(err)
5668 }
5669 for i := range rows {
5670 rows[i].Object.Object = nil
5671 }
5672 if !reflect.DeepEqual(test.expected, rows) {
5673 t.Errorf("%d mismatch: %s", i, cmp.Diff(test.expected, rows))
5674 }
5675 }
5676 }
5677
5678 func TestPrintRuntimeClass(t *testing.T) {
5679 tests := []struct {
5680 rc nodeapi.RuntimeClass
5681 expected []metav1.TableRow
5682 }{
5683 {
5684 rc: nodeapi.RuntimeClass{
5685 ObjectMeta: metav1.ObjectMeta{
5686 Name: "rc1",
5687 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
5688 },
5689 Handler: "h1",
5690 },
5691 expected: []metav1.TableRow{{Cells: []interface{}{"rc1", "h1", "0s"}}},
5692 },
5693 {
5694 rc: nodeapi.RuntimeClass{
5695 ObjectMeta: metav1.ObjectMeta{
5696 Name: "rc2",
5697 CreationTimestamp: metav1.Time{Time: time.Now().Add(-3e11)},
5698 },
5699 Handler: "h2",
5700 },
5701 expected: []metav1.TableRow{{Cells: []interface{}{"rc2", "h2", "5m"}}},
5702 },
5703 }
5704
5705 for i, test := range tests {
5706 rows, err := printRuntimeClass(&test.rc, printers.GenerateOptions{})
5707 if err != nil {
5708 t.Fatal(err)
5709 }
5710 for i := range rows {
5711 rows[i].Object.Object = nil
5712 }
5713 if !reflect.DeepEqual(test.expected, rows) {
5714 t.Errorf("%d mismatch: %s", i, cmp.Diff(test.expected, rows))
5715 }
5716 }
5717 }
5718
5719 func TestPrintEndpoint(t *testing.T) {
5720
5721 tests := []struct {
5722 endpoint api.Endpoints
5723 expected []metav1.TableRow
5724 }{
5725
5726 {
5727 endpoint: api.Endpoints{
5728 ObjectMeta: metav1.ObjectMeta{
5729 Name: "endpoint1",
5730 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
5731 },
5732 },
5733
5734 expected: []metav1.TableRow{{Cells: []interface{}{"endpoint1", "<none>", "0s"}}},
5735 },
5736
5737 {
5738 endpoint: api.Endpoints{
5739 ObjectMeta: metav1.ObjectMeta{
5740 Name: "endpoint3",
5741 CreationTimestamp: metav1.Time{Time: time.Now().Add(-3e11)},
5742 },
5743 Subsets: []api.EndpointSubset{
5744 {
5745 Addresses: []api.EndpointAddress{
5746 {
5747 IP: "1.2.3.4",
5748 },
5749 {
5750 IP: "5.6.7.8",
5751 },
5752 },
5753 },
5754 },
5755 },
5756
5757 expected: []metav1.TableRow{{Cells: []interface{}{"endpoint3", "1.2.3.4,5.6.7.8", "5m"}}},
5758 },
5759
5760 {
5761 endpoint: api.Endpoints{
5762 ObjectMeta: metav1.ObjectMeta{
5763 Name: "endpoint2",
5764 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
5765 },
5766 Subsets: []api.EndpointSubset{
5767 {
5768 Addresses: []api.EndpointAddress{
5769 {
5770 IP: "1.2.3.4",
5771 },
5772 {
5773 IP: "5.6.7.8",
5774 },
5775 },
5776 Ports: []api.EndpointPort{
5777 {
5778 Port: 8001,
5779 Protocol: "tcp",
5780 },
5781 },
5782 },
5783 },
5784 },
5785
5786 expected: []metav1.TableRow{{Cells: []interface{}{"endpoint2", "1.2.3.4:8001,5.6.7.8:8001", "0s"}}},
5787 },
5788
5789 {
5790 endpoint: api.Endpoints{
5791 ObjectMeta: metav1.ObjectMeta{
5792 Name: "endpoint2",
5793 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
5794 },
5795 Subsets: []api.EndpointSubset{
5796 {
5797 Addresses: []api.EndpointAddress{
5798 {
5799 IP: "1.2.3.4",
5800 },
5801 {
5802 IP: "5.6.7.8",
5803 },
5804 {
5805 IP: "9.8.7.6",
5806 },
5807 {
5808 IP: "6.6.6.6",
5809 },
5810 },
5811 Ports: []api.EndpointPort{
5812 {
5813 Port: 8001,
5814 Protocol: "tcp",
5815 },
5816 },
5817 },
5818 },
5819 },
5820
5821 expected: []metav1.TableRow{{Cells: []interface{}{"endpoint2", "1.2.3.4:8001,5.6.7.8:8001,9.8.7.6:8001 + 1 more...", "0s"}}},
5822 },
5823 }
5824
5825 for i, test := range tests {
5826 rows, err := printEndpoints(&test.endpoint, printers.GenerateOptions{})
5827 if err != nil {
5828 t.Fatal(err)
5829 }
5830 for i := range rows {
5831 rows[i].Object.Object = nil
5832 }
5833 if !reflect.DeepEqual(test.expected, rows) {
5834 t.Errorf("%d mismatch: %s", i, cmp.Diff(test.expected, rows))
5835 }
5836 }
5837
5838 }
5839
5840 func TestPrintEndpointSlice(t *testing.T) {
5841 tcpProtocol := api.ProtocolTCP
5842
5843 tests := []struct {
5844 endpointSlice discovery.EndpointSlice
5845 expected []metav1.TableRow
5846 }{
5847 {
5848 endpointSlice: discovery.EndpointSlice{
5849 ObjectMeta: metav1.ObjectMeta{
5850 Name: "abcslice.123",
5851 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
5852 },
5853 AddressType: discovery.AddressTypeIPv4,
5854 Ports: []discovery.EndpointPort{{
5855 Name: utilpointer.StringPtr("http"),
5856 Port: utilpointer.Int32Ptr(80),
5857 Protocol: &tcpProtocol,
5858 }},
5859 Endpoints: []discovery.Endpoint{{
5860 Addresses: []string{"10.1.2.3", "2001:db8::1234:5678"},
5861 }},
5862 },
5863
5864 expected: []metav1.TableRow{{Cells: []interface{}{"abcslice.123", "IPv4", "80", "10.1.2.3,2001:db8::1234:5678", "0s"}}},
5865 }, {
5866 endpointSlice: discovery.EndpointSlice{
5867 ObjectMeta: metav1.ObjectMeta{
5868 Name: "longerslicename.123",
5869 CreationTimestamp: metav1.Time{Time: time.Now().Add(-3e11)},
5870 },
5871 AddressType: discovery.AddressTypeIPv6,
5872 Ports: []discovery.EndpointPort{{
5873 Name: utilpointer.StringPtr("http"),
5874 Port: utilpointer.Int32Ptr(80),
5875 Protocol: &tcpProtocol,
5876 }, {
5877 Name: utilpointer.StringPtr("https"),
5878 Port: utilpointer.Int32Ptr(443),
5879 Protocol: &tcpProtocol,
5880 }},
5881 Endpoints: []discovery.Endpoint{{
5882 Addresses: []string{"10.1.2.3", "2001:db8::1234:5678"},
5883 }, {
5884 Addresses: []string{"10.2.3.4", "2001:db8::2345:6789"},
5885 }},
5886 },
5887
5888 expected: []metav1.TableRow{{Cells: []interface{}{"longerslicename.123", "IPv6", "80,443", "10.1.2.3,2001:db8::1234:5678,10.2.3.4 + 1 more...", "5m"}}},
5889 }, {
5890 endpointSlice: discovery.EndpointSlice{
5891 ObjectMeta: metav1.ObjectMeta{
5892 Name: "multiportslice.123",
5893 CreationTimestamp: metav1.Time{Time: time.Now().Add(-3e11)},
5894 },
5895 AddressType: discovery.AddressTypeIPv4,
5896 Ports: []discovery.EndpointPort{{
5897 Name: utilpointer.StringPtr("http"),
5898 Port: utilpointer.Int32Ptr(80),
5899 Protocol: &tcpProtocol,
5900 }, {
5901 Name: utilpointer.StringPtr("https"),
5902 Port: utilpointer.Int32Ptr(443),
5903 Protocol: &tcpProtocol,
5904 }, {
5905 Name: utilpointer.StringPtr("extra1"),
5906 Port: utilpointer.Int32Ptr(3000),
5907 Protocol: &tcpProtocol,
5908 }, {
5909 Name: utilpointer.StringPtr("extra2"),
5910 Port: utilpointer.Int32Ptr(3001),
5911 Protocol: &tcpProtocol,
5912 }},
5913 Endpoints: []discovery.Endpoint{{
5914 Addresses: []string{"10.1.2.3", "2001:db8::1234:5678"},
5915 }, {
5916 Addresses: []string{"10.2.3.4", "2001:db8::2345:6789"},
5917 }},
5918 },
5919
5920 expected: []metav1.TableRow{{Cells: []interface{}{"multiportslice.123", "IPv4", "80,443,3000 + 1 more...", "10.1.2.3,2001:db8::1234:5678,10.2.3.4 + 1 more...", "5m"}}},
5921 },
5922 }
5923
5924 for i, test := range tests {
5925 rows, err := printEndpointSlice(&test.endpointSlice, printers.GenerateOptions{})
5926 if err != nil {
5927 t.Fatal(err)
5928 }
5929 for i := range rows {
5930 rows[i].Object.Object = nil
5931 }
5932 if !reflect.DeepEqual(test.expected, rows) {
5933 t.Errorf("%d mismatch: %s", i, cmp.Diff(test.expected, rows))
5934 }
5935 }
5936 }
5937
5938 func TestPrintFlowSchema(t *testing.T) {
5939 all := []string{"*"}
5940
5941 tests := []struct {
5942 fs flowcontrol.FlowSchema
5943 expected []metav1.TableRow
5944 }{
5945 {
5946 fs: flowcontrol.FlowSchema{
5947 ObjectMeta: metav1.ObjectMeta{
5948 Name: "all-matcher",
5949 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
5950 },
5951 Spec: flowcontrol.FlowSchemaSpec{
5952 PriorityLevelConfiguration: flowcontrol.PriorityLevelConfigurationReference{Name: "allee"},
5953 MatchingPrecedence: math.MaxInt32,
5954 DistinguisherMethod: &flowcontrol.FlowDistinguisherMethod{Type: flowcontrol.FlowDistinguisherMethodByUserType},
5955 Rules: []flowcontrol.PolicyRulesWithSubjects{{
5956 Subjects: []flowcontrol.Subject{{
5957 Kind: flowcontrol.SubjectKindGroup,
5958 Group: &flowcontrol.GroupSubject{Name: "system:authenticated"},
5959 }},
5960 ResourceRules: []flowcontrol.ResourcePolicyRule{{
5961 Verbs: all,
5962 APIGroups: all,
5963 Resources: all,
5964 ClusterScope: true,
5965 Namespaces: all,
5966 }},
5967 }, {
5968 Subjects: []flowcontrol.Subject{{
5969 Kind: flowcontrol.SubjectKindGroup,
5970 Group: &flowcontrol.GroupSubject{Name: "system:unauthenticated"},
5971 }},
5972 ResourceRules: []flowcontrol.ResourcePolicyRule{{
5973 Verbs: all,
5974 APIGroups: all,
5975 Resources: all,
5976 ClusterScope: true,
5977 Namespaces: all,
5978 }},
5979 }, {
5980 Subjects: []flowcontrol.Subject{{
5981 Kind: flowcontrol.SubjectKindGroup,
5982 Group: &flowcontrol.GroupSubject{Name: "system:authenticated"},
5983 }, {
5984 Kind: flowcontrol.SubjectKindGroup,
5985 Group: &flowcontrol.GroupSubject{Name: "system:unauthenticated"},
5986 }},
5987 NonResourceRules: []flowcontrol.NonResourcePolicyRule{{
5988 Verbs: all,
5989 NonResourceURLs: all,
5990 }},
5991 }},
5992 },
5993 },
5994
5995 expected: []metav1.TableRow{{Cells: []interface{}{"all-matcher", "allee", int64(math.MaxInt32), "ByUser", "0s", "?"}}},
5996 }, {
5997 fs: flowcontrol.FlowSchema{
5998 ObjectMeta: metav1.ObjectMeta{
5999 Name: "some-matcher",
6000 CreationTimestamp: metav1.Time{Time: time.Now().Add(-3e11)},
6001 },
6002 Spec: flowcontrol.FlowSchemaSpec{
6003 PriorityLevelConfiguration: flowcontrol.PriorityLevelConfigurationReference{Name: "allee"},
6004 MatchingPrecedence: 0,
6005 DistinguisherMethod: &flowcontrol.FlowDistinguisherMethod{Type: flowcontrol.FlowDistinguisherMethodByNamespaceType},
6006 Rules: []flowcontrol.PolicyRulesWithSubjects{{
6007 Subjects: []flowcontrol.Subject{{
6008 Kind: flowcontrol.SubjectKindGroup,
6009 Group: &flowcontrol.GroupSubject{Name: "system:unauthenticated"},
6010 }},
6011 ResourceRules: []flowcontrol.ResourcePolicyRule{{
6012 Verbs: all,
6013 APIGroups: all,
6014 Resources: all,
6015 ClusterScope: true,
6016 Namespaces: all,
6017 }},
6018 }, {
6019 Subjects: []flowcontrol.Subject{{
6020 Kind: flowcontrol.SubjectKindGroup,
6021 Group: &flowcontrol.GroupSubject{Name: "system:authenticated"},
6022 }, {
6023 Kind: flowcontrol.SubjectKindGroup,
6024 Group: &flowcontrol.GroupSubject{Name: "system:unauthenticated"},
6025 }},
6026 NonResourceRules: []flowcontrol.NonResourcePolicyRule{{
6027 Verbs: all,
6028 NonResourceURLs: all,
6029 }},
6030 }},
6031 },
6032 Status: flowcontrol.FlowSchemaStatus{
6033 Conditions: []flowcontrol.FlowSchemaCondition{{
6034 Type: flowcontrol.FlowSchemaConditionDangling,
6035 Status: "True",
6036 LastTransitionTime: metav1.Time{Time: time.Now().Add(-time.Hour)},
6037 }},
6038 },
6039 },
6040
6041 expected: []metav1.TableRow{{Cells: []interface{}{"some-matcher", "allee", int64(0), "ByNamespace", "5m", "True"}}},
6042 }, {
6043 fs: flowcontrol.FlowSchema{
6044 ObjectMeta: metav1.ObjectMeta{
6045 Name: "exempt",
6046 CreationTimestamp: metav1.Time{Time: time.Now().Add(-3e11)},
6047 },
6048 Spec: flowcontrol.FlowSchemaSpec{
6049 PriorityLevelConfiguration: flowcontrol.PriorityLevelConfigurationReference{Name: "allee"},
6050 MatchingPrecedence: 0,
6051 DistinguisherMethod: nil,
6052 Rules: []flowcontrol.PolicyRulesWithSubjects{{
6053 Subjects: []flowcontrol.Subject{{
6054 Kind: flowcontrol.SubjectKindGroup,
6055 Group: &flowcontrol.GroupSubject{Name: "system:masters"},
6056 }},
6057 ResourceRules: []flowcontrol.ResourcePolicyRule{{
6058 Verbs: all,
6059 APIGroups: all,
6060 Resources: all,
6061 ClusterScope: true,
6062 Namespaces: all,
6063 }},
6064 }},
6065 },
6066 },
6067
6068 expected: []metav1.TableRow{{Cells: []interface{}{"exempt", "allee", int64(0), "<none>", "5m", "?"}}},
6069 },
6070 }
6071
6072 for i, test := range tests {
6073 rows, err := printFlowSchema(&test.fs, printers.GenerateOptions{})
6074 if err != nil {
6075 t.Fatal(err)
6076 }
6077 for i := range rows {
6078 rows[i].Object.Object = nil
6079 }
6080 if !reflect.DeepEqual(test.expected, rows) {
6081 t.Errorf("%d mismatch: %s", i, cmp.Diff(test.expected, rows))
6082 }
6083 }
6084 }
6085
6086 func TestPrintPriorityLevelConfiguration(t *testing.T) {
6087 tests := []struct {
6088 pl flowcontrol.PriorityLevelConfiguration
6089 expected []metav1.TableRow
6090 }{
6091 {
6092 pl: flowcontrol.PriorityLevelConfiguration{
6093 ObjectMeta: metav1.ObjectMeta{
6094 Name: "unlimited",
6095 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
6096 },
6097 Spec: flowcontrol.PriorityLevelConfigurationSpec{
6098 Type: flowcontrol.PriorityLevelEnablementExempt,
6099 },
6100 },
6101
6102 expected: []metav1.TableRow{{Cells: []interface{}{"unlimited", "Exempt", "<none>", "<none>", "<none>", "<none>", "0s"}}},
6103 },
6104 {
6105 pl: flowcontrol.PriorityLevelConfiguration{
6106 ObjectMeta: metav1.ObjectMeta{
6107 Name: "unqueued",
6108 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
6109 },
6110 Spec: flowcontrol.PriorityLevelConfigurationSpec{
6111 Type: flowcontrol.PriorityLevelEnablementLimited,
6112 Limited: &flowcontrol.LimitedPriorityLevelConfiguration{
6113 NominalConcurrencyShares: 47,
6114 LimitResponse: flowcontrol.LimitResponse{
6115 Type: flowcontrol.LimitResponseTypeReject,
6116 },
6117 },
6118 },
6119 },
6120
6121 expected: []metav1.TableRow{{Cells: []interface{}{"unqueued", "Limited", int32(47), "<none>", "<none>", "<none>", "0s"}}},
6122 },
6123 {
6124 pl: flowcontrol.PriorityLevelConfiguration{
6125 ObjectMeta: metav1.ObjectMeta{
6126 Name: "queued",
6127 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
6128 },
6129 Spec: flowcontrol.PriorityLevelConfigurationSpec{
6130 Type: flowcontrol.PriorityLevelEnablementLimited,
6131 Limited: &flowcontrol.LimitedPriorityLevelConfiguration{
6132 NominalConcurrencyShares: 42,
6133 LimitResponse: flowcontrol.LimitResponse{
6134 Type: flowcontrol.LimitResponseTypeQueue,
6135 Queuing: &flowcontrol.QueuingConfiguration{
6136 Queues: 8,
6137 HandSize: 3,
6138 QueueLengthLimit: 4,
6139 },
6140 },
6141 },
6142 },
6143 },
6144
6145 expected: []metav1.TableRow{{Cells: []interface{}{"queued", "Limited", int32(42), int32(8), int32(3), int32(4), "0s"}}},
6146 },
6147 }
6148
6149 for i, test := range tests {
6150 rows, err := printPriorityLevelConfiguration(&test.pl, printers.GenerateOptions{})
6151 if err != nil {
6152 t.Fatal(err)
6153 }
6154 for i := range rows {
6155 rows[i].Object.Object = nil
6156 }
6157 if !reflect.DeepEqual(test.expected, rows) {
6158 t.Errorf("%d mismatch: %s", i, cmp.Diff(test.expected, rows))
6159 }
6160 }
6161 }
6162
6163 func TestPrintStorageVersion(t *testing.T) {
6164 commonEncodingVersion := "v1"
6165 tests := []struct {
6166 sv apiserverinternal.StorageVersion
6167 expected []metav1.TableRow
6168 }{
6169 {
6170 sv: apiserverinternal.StorageVersion{
6171 ObjectMeta: metav1.ObjectMeta{
6172 Name: "empty",
6173 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
6174 },
6175 Status: apiserverinternal.StorageVersionStatus{},
6176 },
6177
6178 expected: []metav1.TableRow{{Cells: []interface{}{"empty", "<unset>", "<unset>", "0s"}}},
6179 },
6180 {
6181 sv: apiserverinternal.StorageVersion{
6182 ObjectMeta: metav1.ObjectMeta{
6183 Name: "valid",
6184 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
6185 },
6186 Status: apiserverinternal.StorageVersionStatus{
6187 StorageVersions: []apiserverinternal.ServerStorageVersion{
6188 {
6189 APIServerID: "1",
6190 EncodingVersion: "v1",
6191 DecodableVersions: []string{"v1"},
6192 },
6193 {
6194 APIServerID: "2",
6195 EncodingVersion: "v1",
6196 DecodableVersions: []string{"v1", "v2"},
6197 },
6198 },
6199 CommonEncodingVersion: &commonEncodingVersion,
6200 },
6201 },
6202
6203 expected: []metav1.TableRow{{Cells: []interface{}{"valid", "v1", "1=v1,2=v1", "0s"}}},
6204 },
6205 {
6206 sv: apiserverinternal.StorageVersion{
6207 ObjectMeta: metav1.ObjectMeta{
6208 Name: "disagree",
6209 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
6210 },
6211 Status: apiserverinternal.StorageVersionStatus{
6212 StorageVersions: []apiserverinternal.ServerStorageVersion{
6213 {
6214 APIServerID: "1",
6215 EncodingVersion: "v1",
6216 DecodableVersions: []string{"v1"},
6217 },
6218 {
6219 APIServerID: "2",
6220 EncodingVersion: "v1",
6221 DecodableVersions: []string{"v1", "v2"},
6222 },
6223 {
6224 APIServerID: "3",
6225 EncodingVersion: "v2",
6226 DecodableVersions: []string{"v2"},
6227 },
6228 },
6229 },
6230 },
6231
6232 expected: []metav1.TableRow{{Cells: []interface{}{"disagree", "<unset>", "1=v1,2=v1,3=v2", "0s"}}},
6233 },
6234 {
6235 sv: apiserverinternal.StorageVersion{
6236 ObjectMeta: metav1.ObjectMeta{
6237 Name: "agreeWithMore",
6238 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
6239 },
6240 Status: apiserverinternal.StorageVersionStatus{
6241 StorageVersions: []apiserverinternal.ServerStorageVersion{
6242 {
6243 APIServerID: "1",
6244 EncodingVersion: "v1",
6245 DecodableVersions: []string{"v1"},
6246 },
6247 {
6248 APIServerID: "2",
6249 EncodingVersion: "v1",
6250 DecodableVersions: []string{"v1", "v2"},
6251 },
6252 {
6253 APIServerID: "3",
6254 EncodingVersion: "v1",
6255 DecodableVersions: []string{"v1", "v2"},
6256 },
6257 {
6258 APIServerID: "4",
6259 EncodingVersion: "v1",
6260 DecodableVersions: []string{"v1", "v2", "v3alpha1"},
6261 },
6262 },
6263 CommonEncodingVersion: &commonEncodingVersion,
6264 },
6265 },
6266
6267 expected: []metav1.TableRow{{Cells: []interface{}{"agreeWithMore", "v1", "1=v1,2=v1,3=v1 + 1 more...", "0s"}}},
6268 },
6269 }
6270
6271 for i, test := range tests {
6272 rows, err := printStorageVersion(&test.sv, printers.GenerateOptions{})
6273 if err != nil {
6274 t.Fatal(err)
6275 }
6276 for i := range rows {
6277 rows[i].Object.Object = nil
6278 }
6279 if !reflect.DeepEqual(test.expected, rows) {
6280 t.Errorf("%d mismatch: %s", i, cmp.Diff(test.expected, rows))
6281 }
6282 }
6283 }
6284
6285 func TestPrintScale(t *testing.T) {
6286 tests := []struct {
6287 scale autoscaling.Scale
6288 options printers.GenerateOptions
6289 expected []metav1.TableRow
6290 }{
6291 {
6292 scale: autoscaling.Scale{
6293 ObjectMeta: metav1.ObjectMeta{
6294 Name: "test-autoscaling",
6295 CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
6296 },
6297 Spec: autoscaling.ScaleSpec{Replicas: 2},
6298 Status: autoscaling.ScaleStatus{Replicas: 1},
6299 },
6300 expected: []metav1.TableRow{
6301 {
6302 Cells: []interface{}{"test-autoscaling", int64(2), int64(1), string("0s")},
6303 },
6304 },
6305 },
6306 }
6307
6308 for i, test := range tests {
6309 rows, err := printScale(&test.scale, test.options)
6310 if err != nil {
6311 t.Fatal(err)
6312 }
6313 for i := range rows {
6314 rows[i].Object.Object = nil
6315 }
6316 if !reflect.DeepEqual(test.expected, rows) {
6317 t.Errorf("%d mismatch: %s", i, cmp.Diff(test.expected, rows))
6318 }
6319 }
6320 }
6321
6322 func TestTableRowDeepCopyShouldNotPanic(t *testing.T) {
6323 tests := []struct {
6324 name string
6325 printer func() ([]metav1.TableRow, error)
6326 }{
6327 {
6328 name: "Pod",
6329 printer: func() ([]metav1.TableRow, error) {
6330 return printPod(&api.Pod{}, printers.GenerateOptions{})
6331 },
6332 },
6333 {
6334 name: "PodTemplate",
6335 printer: func() ([]metav1.TableRow, error) {
6336 return printPodTemplate(&api.PodTemplate{}, printers.GenerateOptions{})
6337 },
6338 },
6339 {
6340 name: "PodDisruptionBudget",
6341 printer: func() ([]metav1.TableRow, error) {
6342 return printPodDisruptionBudget(&policy.PodDisruptionBudget{}, printers.GenerateOptions{})
6343 },
6344 },
6345 {
6346 name: "ReplicationController",
6347 printer: func() ([]metav1.TableRow, error) {
6348 return printReplicationController(&api.ReplicationController{}, printers.GenerateOptions{})
6349 },
6350 },
6351 {
6352 name: "ReplicaSet",
6353 printer: func() ([]metav1.TableRow, error) {
6354 return printReplicaSet(&apps.ReplicaSet{}, printers.GenerateOptions{})
6355 },
6356 },
6357 {
6358 name: "Job",
6359 printer: func() ([]metav1.TableRow, error) {
6360 return printJob(&batch.Job{}, printers.GenerateOptions{})
6361 },
6362 },
6363 {
6364 name: "CronJob",
6365 printer: func() ([]metav1.TableRow, error) {
6366 return printCronJob(&batch.CronJob{}, printers.GenerateOptions{})
6367 },
6368 },
6369 {
6370 name: "Service",
6371 printer: func() ([]metav1.TableRow, error) {
6372 return printService(&api.Service{}, printers.GenerateOptions{})
6373 },
6374 },
6375 {
6376 name: "Ingress",
6377 printer: func() ([]metav1.TableRow, error) {
6378 return printIngress(&networking.Ingress{}, printers.GenerateOptions{})
6379 },
6380 },
6381 {
6382 name: "IngressClass",
6383 printer: func() ([]metav1.TableRow, error) {
6384 return printIngressClass(&networking.IngressClass{}, printers.GenerateOptions{})
6385 },
6386 },
6387 {
6388 name: "StatefulSet",
6389 printer: func() ([]metav1.TableRow, error) {
6390 return printStatefulSet(&apps.StatefulSet{}, printers.GenerateOptions{})
6391 },
6392 },
6393 {
6394 name: "DaemonSet",
6395 printer: func() ([]metav1.TableRow, error) {
6396 return printDaemonSet(&apps.DaemonSet{}, printers.GenerateOptions{})
6397 },
6398 },
6399 {
6400 name: "Endpoints",
6401 printer: func() ([]metav1.TableRow, error) {
6402 return printEndpoints(&api.Endpoints{}, printers.GenerateOptions{})
6403 },
6404 },
6405 {
6406 name: "EndpointSlice",
6407 printer: func() ([]metav1.TableRow, error) {
6408 return printEndpointSlice(&discovery.EndpointSlice{}, printers.GenerateOptions{})
6409 },
6410 },
6411 {
6412 name: "CSINode",
6413 printer: func() ([]metav1.TableRow, error) {
6414 return printCSINode(&storage.CSINode{}, printers.GenerateOptions{})
6415 },
6416 },
6417 {
6418 name: "CSIDriver",
6419 printer: func() ([]metav1.TableRow, error) {
6420 return printCSIDriver(&storage.CSIDriver{}, printers.GenerateOptions{})
6421 },
6422 },
6423 {
6424 name: "CSIStorageCapacity",
6425 printer: func() ([]metav1.TableRow, error) {
6426 return printCSIStorageCapacity(&storage.CSIStorageCapacity{}, printers.GenerateOptions{})
6427 },
6428 },
6429 {
6430 name: "MutatingWebhookConfiguration",
6431 printer: func() ([]metav1.TableRow, error) {
6432 return printMutatingWebhook(&admissionregistration.MutatingWebhookConfiguration{}, printers.GenerateOptions{})
6433 },
6434 },
6435 {
6436 name: "ValidatingWebhookConfiguration",
6437 printer: func() ([]metav1.TableRow, error) {
6438 return printValidatingWebhook(&admissionregistration.ValidatingWebhookConfiguration{}, printers.GenerateOptions{})
6439 },
6440 },
6441 {
6442 name: "ValidatingAdmissionPolicy",
6443 printer: func() ([]metav1.TableRow, error) {
6444 return printValidatingAdmissionPolicy(&admissionregistration.ValidatingAdmissionPolicy{}, printers.GenerateOptions{})
6445 },
6446 },
6447 {
6448 name: "ValidatingAdmissionPolicyBinding",
6449 printer: func() ([]metav1.TableRow, error) {
6450 return printValidatingAdmissionPolicyBinding(&admissionregistration.ValidatingAdmissionPolicyBinding{}, printers.GenerateOptions{})
6451 },
6452 },
6453 {
6454 name: "Namespace",
6455 printer: func() ([]metav1.TableRow, error) {
6456 return printNamespace(&api.Namespace{}, printers.GenerateOptions{})
6457 },
6458 },
6459 {
6460 name: "Secret",
6461 printer: func() ([]metav1.TableRow, error) {
6462 return printSecret(&api.Secret{}, printers.GenerateOptions{})
6463 },
6464 },
6465 {
6466 name: "ServiceAccount",
6467 printer: func() ([]metav1.TableRow, error) {
6468 return printServiceAccount(&api.ServiceAccount{}, printers.GenerateOptions{})
6469 },
6470 },
6471 {
6472 name: "Node",
6473 printer: func() ([]metav1.TableRow, error) {
6474 return printNode(&api.Node{}, printers.GenerateOptions{})
6475 },
6476 },
6477 {
6478 name: "PersistentVolume",
6479 printer: func() ([]metav1.TableRow, error) {
6480 return printPersistentVolume(&api.PersistentVolume{}, printers.GenerateOptions{})
6481 },
6482 },
6483 {
6484 name: "PersistentVolumeClaim",
6485 printer: func() ([]metav1.TableRow, error) {
6486 return printPersistentVolumeClaim(&api.PersistentVolumeClaim{}, printers.GenerateOptions{})
6487 },
6488 },
6489 {
6490 name: "Event",
6491 printer: func() ([]metav1.TableRow, error) {
6492 return printEvent(&api.Event{}, printers.GenerateOptions{})
6493 },
6494 },
6495 {
6496 name: "RoleBinding",
6497 printer: func() ([]metav1.TableRow, error) {
6498 return printRoleBinding(&rbac.RoleBinding{}, printers.GenerateOptions{})
6499 },
6500 },
6501 {
6502 name: "ClusterRoleBinding",
6503 printer: func() ([]metav1.TableRow, error) {
6504 return printClusterRoleBinding(&rbac.ClusterRoleBinding{}, printers.GenerateOptions{})
6505 },
6506 },
6507 {
6508 name: "CertificateSigningRequest",
6509 printer: func() ([]metav1.TableRow, error) {
6510 return printCertificateSigningRequest(&certificates.CertificateSigningRequest{}, printers.GenerateOptions{})
6511 },
6512 },
6513 {
6514 name: "ComponentStatus",
6515 printer: func() ([]metav1.TableRow, error) {
6516 return printComponentStatus(&api.ComponentStatus{}, printers.GenerateOptions{})
6517 },
6518 },
6519 {
6520 name: "Deployment",
6521 printer: func() ([]metav1.TableRow, error) {
6522 return printDeployment(&apps.Deployment{}, printers.GenerateOptions{})
6523 },
6524 },
6525 {
6526 name: "HorizontalPodAutoscaler",
6527 printer: func() ([]metav1.TableRow, error) {
6528 return printHorizontalPodAutoscaler(&autoscaling.HorizontalPodAutoscaler{}, printers.GenerateOptions{})
6529 },
6530 },
6531 {
6532 name: "ConfigMap",
6533 printer: func() ([]metav1.TableRow, error) {
6534 return printConfigMap(&api.ConfigMap{}, printers.GenerateOptions{})
6535 },
6536 },
6537 {
6538 name: "NetworkPolicy",
6539 printer: func() ([]metav1.TableRow, error) {
6540 return printNetworkPolicy(&networking.NetworkPolicy{}, printers.GenerateOptions{})
6541 },
6542 },
6543 {
6544 name: "StorageClass",
6545 printer: func() ([]metav1.TableRow, error) {
6546 return printStorageClass(&storage.StorageClass{}, printers.GenerateOptions{})
6547 },
6548 },
6549 {
6550 name: "Lease",
6551 printer: func() ([]metav1.TableRow, error) {
6552 return printLease(&coordination.Lease{}, printers.GenerateOptions{})
6553 },
6554 },
6555 {
6556 name: "ControllerRevision",
6557 printer: func() ([]metav1.TableRow, error) {
6558 return printControllerRevision(&apps.ControllerRevision{}, printers.GenerateOptions{})
6559 },
6560 },
6561 {
6562 name: "ResourceQuota",
6563 printer: func() ([]metav1.TableRow, error) {
6564 return printResourceQuota(&api.ResourceQuota{}, printers.GenerateOptions{})
6565 },
6566 },
6567 {
6568 name: "PriorityClass",
6569 printer: func() ([]metav1.TableRow, error) {
6570 return printPriorityClass(&scheduling.PriorityClass{}, printers.GenerateOptions{})
6571 },
6572 },
6573 {
6574 name: "RuntimeClass",
6575 printer: func() ([]metav1.TableRow, error) {
6576 return printRuntimeClass(&nodeapi.RuntimeClass{}, printers.GenerateOptions{})
6577 },
6578 },
6579 {
6580 name: "VolumeAttachment",
6581 printer: func() ([]metav1.TableRow, error) {
6582 return printVolumeAttachment(&storage.VolumeAttachment{}, printers.GenerateOptions{})
6583 },
6584 },
6585 {
6586 name: "FlowSchema",
6587 printer: func() ([]metav1.TableRow, error) {
6588 return printFlowSchema(&flowcontrol.FlowSchema{}, printers.GenerateOptions{})
6589 },
6590 },
6591 {
6592 name: "StorageVersion",
6593 printer: func() ([]metav1.TableRow, error) {
6594 return printStorageVersion(&apiserverinternal.StorageVersion{}, printers.GenerateOptions{})
6595 },
6596 },
6597 {
6598 name: "PriorityLevelConfiguration",
6599 printer: func() ([]metav1.TableRow, error) {
6600 return printPriorityLevelConfiguration(&flowcontrol.PriorityLevelConfiguration{}, printers.GenerateOptions{})
6601 },
6602 },
6603 {
6604 name: "Scale",
6605 printer: func() ([]metav1.TableRow, error) {
6606 return printScale(&autoscaling.Scale{}, printers.GenerateOptions{})
6607 },
6608 },
6609 {
6610 name: "Status",
6611 printer: func() ([]metav1.TableRow, error) {
6612 return printStatus(&metav1.Status{}, printers.GenerateOptions{})
6613 },
6614 },
6615 }
6616
6617 for _, test := range tests {
6618 t.Run(test.name, func(t *testing.T) {
6619 rows, err := test.printer()
6620 if err != nil {
6621 t.Fatalf("expected no error, but got: %#v", err)
6622 }
6623 if len(rows) <= 0 {
6624 t.Fatalf("expected to have at least one TableRow, but got: %d", len(rows))
6625 }
6626
6627 func() {
6628 defer func() {
6629 if err := recover(); err != nil {
6630
6631
6632 const size = 64 << 10
6633 buf := make([]byte, size)
6634 buf = buf[:runtime.Stack(buf, false)]
6635 err = fmt.Errorf("%q stack:\n%s", err, buf)
6636
6637 t.Errorf("Expected no panic, but got: %v", err)
6638 }
6639 }()
6640
6641
6642 rows[0].DeepCopy()
6643 }()
6644
6645 })
6646 }
6647 }
6648
6649 func TestPrintIPAddress(t *testing.T) {
6650 ip := networking.IPAddress{
6651 ObjectMeta: metav1.ObjectMeta{
6652 Name: "192.168.2.2",
6653 CreationTimestamp: metav1.Time{Time: time.Now().AddDate(-10, 0, 0)},
6654 },
6655 Spec: networking.IPAddressSpec{
6656 ParentRef: &networking.ParentReference{
6657 Group: "mygroup",
6658 Resource: "myresource",
6659 Namespace: "mynamespace",
6660 Name: "myname",
6661 },
6662 },
6663 }
6664
6665 expected := []metav1.TableRow{{Cells: []interface{}{"192.168.2.2", "myresource.mygroup/mynamespace/myname", "10y"}}}
6666
6667 rows, err := printIPAddress(&ip, printers.GenerateOptions{})
6668 if err != nil {
6669 t.Fatalf("Error generating table rows for IPAddress: %#v", err)
6670 }
6671 rows[0].Object.Object = nil
6672 if !reflect.DeepEqual(expected, rows) {
6673 t.Errorf("mismatch: %s", cmp.Diff(expected, rows))
6674 }
6675 }
6676
6677 func TestPrintIPAddressList(t *testing.T) {
6678 ipList := networking.IPAddressList{
6679 Items: []networking.IPAddress{
6680 {
6681 ObjectMeta: metav1.ObjectMeta{
6682 Name: "192.168.2.2",
6683 CreationTimestamp: metav1.Time{},
6684 },
6685 Spec: networking.IPAddressSpec{
6686 ParentRef: &networking.ParentReference{
6687 Group: "mygroup",
6688 Resource: "myresource",
6689 Namespace: "mynamespace",
6690 Name: "myname",
6691 },
6692 },
6693 }, {
6694 ObjectMeta: metav1.ObjectMeta{
6695 Name: "2001:db8::2",
6696 CreationTimestamp: metav1.Time{},
6697 },
6698 Spec: networking.IPAddressSpec{
6699 ParentRef: &networking.ParentReference{
6700 Group: "mygroup2",
6701 Resource: "myresource2",
6702 Namespace: "mynamespace2",
6703 Name: "myname2",
6704 },
6705 },
6706 },
6707 },
6708 }
6709
6710 expected := []metav1.TableRow{
6711 {Cells: []interface{}{"192.168.2.2", "myresource.mygroup/mynamespace/myname", "<unknown>"}},
6712 {Cells: []interface{}{"2001:db8::2", "myresource2.mygroup2/mynamespace2/myname2", "<unknown>"}},
6713 }
6714
6715 rows, err := printIPAddressList(&ipList, printers.GenerateOptions{})
6716 if err != nil {
6717 t.Fatalf("Error generating table rows for IPAddress: %#v", err)
6718 }
6719 for i := range rows {
6720 rows[i].Object.Object = nil
6721
6722 }
6723 if !reflect.DeepEqual(expected, rows) {
6724 t.Errorf("mismatch: %s", cmp.Diff(expected, rows))
6725 }
6726
6727 }
6728
6729 func TestPrintServiceCIDR(t *testing.T) {
6730 ipv4CIDR := "10.1.0.0/16"
6731 ipv6CIDR := "fd00:1:1::/64"
6732
6733 tests := []struct {
6734 ccc networking.ServiceCIDR
6735 options printers.GenerateOptions
6736 expected []metav1.TableRow
6737 }{
6738 {
6739
6740 ccc: networking.ServiceCIDR{
6741 ObjectMeta: metav1.ObjectMeta{Name: "test1"},
6742 Spec: networking.ServiceCIDRSpec{
6743 CIDRs: []string{ipv4CIDR},
6744 },
6745 },
6746 options: printers.GenerateOptions{},
6747
6748 expected: []metav1.TableRow{{Cells: []interface{}{"test1", ipv4CIDR, "<unknown>"}}},
6749 },
6750 {
6751
6752 ccc: networking.ServiceCIDR{
6753 ObjectMeta: metav1.ObjectMeta{Name: "test5"},
6754 Spec: networking.ServiceCIDRSpec{
6755 CIDRs: []string{ipv6CIDR},
6756 },
6757 },
6758 options: printers.GenerateOptions{},
6759
6760 expected: []metav1.TableRow{{Cells: []interface{}{"test5", ipv6CIDR, "<unknown>"}}},
6761 },
6762 {
6763
6764 ccc: networking.ServiceCIDR{
6765 ObjectMeta: metav1.ObjectMeta{Name: "test9"},
6766 Spec: networking.ServiceCIDRSpec{
6767 CIDRs: []string{ipv4CIDR, ipv6CIDR},
6768 },
6769 },
6770 options: printers.GenerateOptions{},
6771
6772 expected: []metav1.TableRow{{Cells: []interface{}{"test9", ipv4CIDR + "," + ipv6CIDR, "<unknown>"}}},
6773 },
6774 }
6775
6776 for i, test := range tests {
6777 rows, err := printServiceCIDR(&test.ccc, test.options)
6778 if err != nil {
6779 t.Fatal(err)
6780 }
6781 for i := range rows {
6782 rows[i].Object.Object = nil
6783 }
6784 if !reflect.DeepEqual(test.expected, rows) {
6785 t.Errorf("%d mismatch: %s", i, cmp.Diff(test.expected, rows))
6786 }
6787 }
6788 }
6789
6790 func TestPrintServiceCIDRList(t *testing.T) {
6791 cccList := networking.ServiceCIDRList{
6792 Items: []networking.ServiceCIDR{
6793 {
6794 ObjectMeta: metav1.ObjectMeta{Name: "ccc1"},
6795 Spec: networking.ServiceCIDRSpec{
6796 CIDRs: []string{"10.1.0.0/16", "fd00:1:1::/64"},
6797 },
6798 },
6799 {
6800 ObjectMeta: metav1.ObjectMeta{Name: "ccc2"},
6801 Spec: networking.ServiceCIDRSpec{
6802 CIDRs: []string{"10.2.0.0/16", "fd00:2:1::/64"},
6803 },
6804 },
6805 },
6806 }
6807
6808 tests := []struct {
6809 options printers.GenerateOptions
6810 expected []metav1.TableRow
6811 }{
6812 {
6813
6814 options: printers.GenerateOptions{Wide: false},
6815 expected: []metav1.TableRow{
6816
6817 {Cells: []interface{}{"ccc1", "10.1.0.0/16,fd00:1:1::/64", "<unknown>"}},
6818 {Cells: []interface{}{"ccc2", "10.2.0.0/16,fd00:2:1::/64", "<unknown>"}},
6819 },
6820 },
6821 {
6822
6823 options: printers.GenerateOptions{Wide: true},
6824 expected: []metav1.TableRow{
6825
6826 {Cells: []interface{}{"ccc1", "10.1.0.0/16,fd00:1:1::/64", "<unknown>"}},
6827 {Cells: []interface{}{"ccc2", "10.2.0.0/16,fd00:2:1::/64", "<unknown>"}},
6828 },
6829 },
6830 }
6831
6832 for _, test := range tests {
6833 rows, err := printServiceCIDRList(&cccList, test.options)
6834 if err != nil {
6835 t.Fatalf("Error printing service list: %#v", err)
6836 }
6837 for i := range rows {
6838 rows[i].Object.Object = nil
6839 }
6840 if !reflect.DeepEqual(test.expected, rows) {
6841 t.Errorf("mismatch: %s", cmp.Diff(test.expected, rows))
6842 }
6843 }
6844 }
6845
6846 func TestPrintStorageVersionMigration(t *testing.T) {
6847 storageVersionMigration := storagemigration.StorageVersionMigration{
6848 TypeMeta: metav1.TypeMeta{
6849 Kind: "StorageVersionMigration",
6850 APIVersion: "storagemigration.k8s.io/v1alpha1",
6851 },
6852 ObjectMeta: metav1.ObjectMeta{
6853 Name: "print-test",
6854 },
6855 Spec: storagemigration.StorageVersionMigrationSpec{
6856 Resource: storagemigration.GroupVersionResource{
6857 Group: "test-group",
6858 Version: "test-version",
6859 Resource: "test-resource",
6860 },
6861 },
6862 }
6863
6864
6865 expected := []metav1.TableRow{{Cells: []interface{}{"print-test", "test-resource.test-version.test-group"}}}
6866
6867 rows, err := printStorageVersionMigration(&storageVersionMigration, printers.GenerateOptions{})
6868 if err != nil {
6869 t.Fatalf("Error generating table rows for StorageVersionMigration: %#v", err)
6870 }
6871 rows[0].Object.Object = nil
6872 if !reflect.DeepEqual(expected, rows) {
6873 t.Errorf("mismatch: %s", cmp.Diff(expected, rows))
6874 }
6875 }
6876
6877 func TestPrintStorageVersionMigrationList(t *testing.T) {
6878 storageVersionMigrationList := storagemigration.StorageVersionMigrationList{
6879 Items: []storagemigration.StorageVersionMigration{
6880 {
6881 TypeMeta: metav1.TypeMeta{
6882 Kind: "StorageVersionMigration",
6883 APIVersion: "storagemigration.k8s.io/v1alpha1",
6884 },
6885 ObjectMeta: metav1.ObjectMeta{
6886 Name: "print-test",
6887 },
6888 Spec: storagemigration.StorageVersionMigrationSpec{
6889 Resource: storagemigration.GroupVersionResource{
6890 Group: "test-group",
6891 Version: "test-version",
6892 Resource: "test-resource",
6893 },
6894 },
6895 },
6896 {
6897 TypeMeta: metav1.TypeMeta{
6898 Kind: "StorageVersionMigration",
6899 APIVersion: "storagemigration.k8s.io/v1alpha1",
6900 },
6901 ObjectMeta: metav1.ObjectMeta{
6902 Name: "print-test2",
6903 },
6904 Spec: storagemigration.StorageVersionMigrationSpec{
6905 Resource: storagemigration.GroupVersionResource{
6906 Group: "test-group2",
6907 Version: "test-version2",
6908 Resource: "test-resource2",
6909 },
6910 },
6911 },
6912 },
6913 }
6914
6915
6916 expected := []metav1.TableRow{
6917 {Cells: []interface{}{"print-test", "test-resource.test-version.test-group"}},
6918 {Cells: []interface{}{"print-test2", "test-resource2.test-version2.test-group2"}},
6919 }
6920
6921 rows, err := printStorageVersionMigrationList(&storageVersionMigrationList, printers.GenerateOptions{})
6922 if err != nil {
6923 t.Fatalf("Error generating table rows for StorageVersionMigration: %#v", err)
6924 }
6925
6926 for i := range rows {
6927 rows[i].Object.Object = nil
6928 }
6929
6930 if !reflect.DeepEqual(expected, rows) {
6931 t.Errorf("mismatch: %s", cmp.Diff(expected, rows))
6932 }
6933 }
6934
View as plain text