k8s.io/kubernetes@v1.29.3/pkg/util/pod/pod_test.go (about) 1 /* 2 Copyright 2018 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package pod 18 19 import ( 20 "context" 21 "fmt" 22 "testing" 23 24 "reflect" 25 26 "github.com/google/go-cmp/cmp" 27 v1 "k8s.io/api/core/v1" 28 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 29 "k8s.io/apimachinery/pkg/types" 30 "k8s.io/client-go/kubernetes/fake" 31 ) 32 33 func TestPatchPodStatus(t *testing.T) { 34 ns := "ns" 35 name := "name" 36 uid := types.UID("myuid") 37 client := &fake.Clientset{} 38 client.CoreV1().Pods(ns).Create(context.TODO(), &v1.Pod{ 39 ObjectMeta: metav1.ObjectMeta{ 40 Namespace: ns, 41 Name: name, 42 }, 43 }, metav1.CreateOptions{}) 44 45 testCases := []struct { 46 description string 47 mutate func(input v1.PodStatus) v1.PodStatus 48 expectUnchanged bool 49 expectedPatchBytes []byte 50 }{ 51 { 52 "no change", 53 func(input v1.PodStatus) v1.PodStatus { return input }, 54 true, 55 []byte(fmt.Sprintf(`{"metadata":{"uid":"myuid"}}`)), 56 }, 57 { 58 "message change", 59 func(input v1.PodStatus) v1.PodStatus { 60 input.Message = "random message" 61 return input 62 }, 63 false, 64 []byte(fmt.Sprintf(`{"metadata":{"uid":"myuid"},"status":{"message":"random message"}}`)), 65 }, 66 { 67 "pod condition change", 68 func(input v1.PodStatus) v1.PodStatus { 69 input.Conditions[0].Status = v1.ConditionFalse 70 return input 71 }, 72 false, 73 []byte(fmt.Sprintf(`{"metadata":{"uid":"myuid"},"status":{"$setElementOrder/conditions":[{"type":"Ready"},{"type":"PodScheduled"}],"conditions":[{"status":"False","type":"Ready"}]}}`)), 74 }, 75 { 76 "additional init container condition", 77 func(input v1.PodStatus) v1.PodStatus { 78 input.InitContainerStatuses = []v1.ContainerStatus{ 79 { 80 Name: "init-container", 81 Ready: true, 82 }, 83 } 84 return input 85 }, 86 false, 87 []byte(fmt.Sprintf(`{"metadata":{"uid":"myuid"},"status":{"initContainerStatuses":[{"image":"","imageID":"","lastState":{},"name":"init-container","ready":true,"restartCount":0,"state":{}}]}}`)), 88 }, 89 } 90 for _, tc := range testCases { 91 t.Run(tc.description, func(t *testing.T) { 92 _, patchBytes, unchanged, err := PatchPodStatus(context.TODO(), client, ns, name, uid, getPodStatus(), tc.mutate(getPodStatus())) 93 if err != nil { 94 t.Errorf("unexpected error: %v", err) 95 } 96 if unchanged != tc.expectUnchanged { 97 t.Errorf("unexpected change: %t", unchanged) 98 } 99 if !reflect.DeepEqual(patchBytes, tc.expectedPatchBytes) { 100 t.Errorf("expect patchBytes: %q, got: %q\n", tc.expectedPatchBytes, patchBytes) 101 } 102 }) 103 } 104 } 105 106 func getPodStatus() v1.PodStatus { 107 return v1.PodStatus{ 108 Phase: v1.PodRunning, 109 Conditions: []v1.PodCondition{ 110 { 111 Type: v1.PodReady, 112 Status: v1.ConditionTrue, 113 }, 114 { 115 Type: v1.PodScheduled, 116 Status: v1.ConditionTrue, 117 }, 118 }, 119 ContainerStatuses: []v1.ContainerStatus{ 120 { 121 Name: "container1", 122 Ready: true, 123 }, 124 { 125 Name: "container2", 126 Ready: true, 127 }, 128 }, 129 Message: "Message", 130 } 131 } 132 133 func TestReplaceOrAppendPodCondition(t *testing.T) { 134 cType := v1.PodConditionType("ExampleType") 135 testCases := []struct { 136 description string 137 conditions []v1.PodCondition 138 condition v1.PodCondition 139 wantConditions []v1.PodCondition 140 }{ 141 { 142 description: "append", 143 conditions: []v1.PodCondition{}, 144 condition: v1.PodCondition{ 145 Type: cType, 146 Status: v1.ConditionTrue, 147 }, 148 wantConditions: []v1.PodCondition{ 149 { 150 Type: cType, 151 Status: v1.ConditionTrue, 152 }, 153 }, 154 }, 155 { 156 description: "replace", 157 conditions: []v1.PodCondition{ 158 { 159 Type: cType, 160 Status: v1.ConditionTrue, 161 }, 162 }, 163 condition: v1.PodCondition{ 164 Type: cType, 165 Status: v1.ConditionFalse, 166 }, 167 wantConditions: []v1.PodCondition{ 168 { 169 Type: cType, 170 Status: v1.ConditionFalse, 171 }, 172 }, 173 }, 174 } 175 for _, tc := range testCases { 176 t.Run(tc.description, func(t *testing.T) { 177 gotConditions := ReplaceOrAppendPodCondition(tc.conditions, &tc.condition) 178 if diff := cmp.Diff(tc.wantConditions, gotConditions); diff != "" { 179 t.Errorf("Unexpected conditions: %s", diff) 180 } 181 }) 182 } 183 }