k8s.io/kubernetes@v1.29.3/pkg/kubelet/kuberuntime/helpers_test.go (about) 1 /* 2 Copyright 2016 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 kuberuntime 18 19 import ( 20 "context" 21 "testing" 22 23 "github.com/stretchr/testify/assert" 24 25 v1 "k8s.io/api/core/v1" 26 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 27 "k8s.io/apimachinery/pkg/types" 28 utilfeature "k8s.io/apiserver/pkg/util/feature" 29 featuregatetesting "k8s.io/component-base/featuregate/testing" 30 runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1" 31 runtimetesting "k8s.io/cri-api/pkg/apis/testing" 32 "k8s.io/kubernetes/pkg/features" 33 kubecontainer "k8s.io/kubernetes/pkg/kubelet/container" 34 ) 35 36 type podStatusProviderFunc func(uid types.UID, name, namespace string) (*kubecontainer.PodStatus, error) 37 38 func (f podStatusProviderFunc) GetPodStatus(_ context.Context, uid types.UID, name, namespace string) (*kubecontainer.PodStatus, error) { 39 return f(uid, name, namespace) 40 } 41 42 func TestIsInitContainerFailed(t *testing.T) { 43 tests := []struct { 44 status *kubecontainer.Status 45 isFailed bool 46 description string 47 }{ 48 { 49 status: &kubecontainer.Status{ 50 State: kubecontainer.ContainerStateExited, 51 ExitCode: 1, 52 }, 53 isFailed: true, 54 description: "Init container in exited state and non-zero exit code should return true", 55 }, 56 { 57 status: &kubecontainer.Status{ 58 State: kubecontainer.ContainerStateUnknown, 59 }, 60 isFailed: true, 61 description: "Init container in unknown state should return true", 62 }, 63 { 64 status: &kubecontainer.Status{ 65 Reason: "OOMKilled", 66 ExitCode: 0, 67 }, 68 isFailed: true, 69 description: "Init container which reason is OOMKilled should return true", 70 }, 71 { 72 status: &kubecontainer.Status{ 73 State: kubecontainer.ContainerStateExited, 74 ExitCode: 0, 75 }, 76 isFailed: false, 77 description: "Init container in exited state and zero exit code should return false", 78 }, 79 { 80 status: &kubecontainer.Status{ 81 State: kubecontainer.ContainerStateRunning, 82 }, 83 isFailed: false, 84 description: "Init container in running state should return false", 85 }, 86 { 87 status: &kubecontainer.Status{ 88 State: kubecontainer.ContainerStateCreated, 89 }, 90 isFailed: false, 91 description: "Init container in created state should return false", 92 }, 93 } 94 for i, test := range tests { 95 isFailed := isInitContainerFailed(test.status) 96 assert.Equal(t, test.isFailed, isFailed, "TestCase[%d]: %s", i, test.description) 97 } 98 } 99 100 func TestStableKey(t *testing.T) { 101 container := &v1.Container{ 102 Name: "test_container", 103 Image: "foo/image:v1", 104 } 105 pod := &v1.Pod{ 106 ObjectMeta: metav1.ObjectMeta{ 107 Name: "test_pod", 108 Namespace: "test_pod_namespace", 109 UID: "test_pod_uid", 110 }, 111 Spec: v1.PodSpec{ 112 Containers: []v1.Container{*container}, 113 }, 114 } 115 oldKey := getStableKey(pod, container) 116 117 // Updating the container image should change the key. 118 container.Image = "foo/image:v2" 119 newKey := getStableKey(pod, container) 120 assert.NotEqual(t, oldKey, newKey) 121 } 122 123 func TestToKubeContainer(t *testing.T) { 124 c := &runtimeapi.Container{ 125 Id: "test-id", 126 Metadata: &runtimeapi.ContainerMetadata{ 127 Name: "test-name", 128 Attempt: 1, 129 }, 130 Image: &runtimeapi.ImageSpec{Image: "test-image"}, 131 ImageRef: "test-image-ref", 132 State: runtimeapi.ContainerState_CONTAINER_RUNNING, 133 Annotations: map[string]string{ 134 containerHashLabel: "1234", 135 }, 136 } 137 expect := &kubecontainer.Container{ 138 ID: kubecontainer.ContainerID{ 139 Type: runtimetesting.FakeRuntimeName, 140 ID: "test-id", 141 }, 142 Name: "test-name", 143 ImageID: "test-image-ref", 144 Image: "test-image", 145 ImageRuntimeHandler: "", 146 Hash: uint64(0x1234), 147 State: kubecontainer.ContainerStateRunning, 148 } 149 150 _, _, m, err := createTestRuntimeManager() 151 assert.NoError(t, err) 152 got, err := m.toKubeContainer(c) 153 assert.NoError(t, err) 154 assert.Equal(t, expect, got) 155 156 // unable to convert a nil pointer to a runtime container 157 _, err = m.toKubeContainer(nil) 158 assert.Error(t, err) 159 _, err = m.sandboxToKubeContainer(nil) 160 assert.Error(t, err) 161 } 162 163 func TestToKubeContainerWithRuntimeHandlerInImageSpecCri(t *testing.T) { 164 defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.RuntimeClassInImageCriAPI, true)() 165 c := &runtimeapi.Container{ 166 Id: "test-id", 167 Metadata: &runtimeapi.ContainerMetadata{ 168 Name: "test-name", 169 Attempt: 1, 170 }, 171 Image: &runtimeapi.ImageSpec{Image: "test-image", RuntimeHandler: "test-runtimeHandler"}, 172 ImageRef: "test-image-ref", 173 State: runtimeapi.ContainerState_CONTAINER_RUNNING, 174 Annotations: map[string]string{ 175 containerHashLabel: "1234", 176 }, 177 } 178 expect := &kubecontainer.Container{ 179 ID: kubecontainer.ContainerID{ 180 Type: runtimetesting.FakeRuntimeName, 181 ID: "test-id", 182 }, 183 Name: "test-name", 184 ImageID: "test-image-ref", 185 Image: "test-image", 186 ImageRuntimeHandler: "test-runtimeHandler", 187 Hash: uint64(0x1234), 188 State: kubecontainer.ContainerStateRunning, 189 } 190 191 _, _, m, err := createTestRuntimeManager() 192 assert.NoError(t, err) 193 got, err := m.toKubeContainer(c) 194 assert.NoError(t, err) 195 assert.Equal(t, expect, got) 196 197 // unable to convert a nil pointer to a runtime container 198 _, err = m.toKubeContainer(nil) 199 assert.Error(t, err) 200 _, err = m.sandboxToKubeContainer(nil) 201 assert.Error(t, err) 202 } 203 204 func TestGetImageUser(t *testing.T) { 205 _, i, m, err := createTestRuntimeManager() 206 assert.NoError(t, err) 207 208 type image struct { 209 name string 210 uid *runtimeapi.Int64Value 211 username string 212 } 213 214 type imageUserValues struct { 215 // getImageUser can return (*int64)(nil) so comparing with *uid will break 216 // type cannot be *int64 as Golang does not allow to take the address of a numeric constant" 217 uid interface{} 218 username string 219 err error 220 } 221 222 tests := []struct { 223 description string 224 originalImage image 225 expectedImageUserValues imageUserValues 226 }{ 227 { 228 "image without username and uid should return (new(int64), \"\", nil)", 229 image{ 230 name: "test-image-ref1", 231 uid: (*runtimeapi.Int64Value)(nil), 232 username: "", 233 }, 234 imageUserValues{ 235 uid: int64(0), 236 username: "", 237 err: nil, 238 }, 239 }, 240 { 241 "image with username and no uid should return ((*int64)nil, imageStatus.Username, nil)", 242 image{ 243 name: "test-image-ref2", 244 uid: (*runtimeapi.Int64Value)(nil), 245 username: "testUser", 246 }, 247 imageUserValues{ 248 uid: (*int64)(nil), 249 username: "testUser", 250 err: nil, 251 }, 252 }, 253 { 254 "image with uid should return (*int64, \"\", nil)", 255 image{ 256 name: "test-image-ref3", 257 uid: &runtimeapi.Int64Value{ 258 Value: 2, 259 }, 260 username: "whatever", 261 }, 262 imageUserValues{ 263 uid: int64(2), 264 username: "", 265 err: nil, 266 }, 267 }, 268 } 269 270 i.SetFakeImages([]string{"test-image-ref1", "test-image-ref2", "test-image-ref3"}) 271 for j, test := range tests { 272 ctx := context.Background() 273 i.Images[test.originalImage.name].Username = test.originalImage.username 274 i.Images[test.originalImage.name].Uid = test.originalImage.uid 275 276 uid, username, err := m.getImageUser(ctx, test.originalImage.name) 277 assert.NoError(t, err, "TestCase[%d]", j) 278 279 if test.expectedImageUserValues.uid == (*int64)(nil) { 280 assert.Equal(t, test.expectedImageUserValues.uid, uid, "TestCase[%d]", j) 281 } else { 282 assert.Equal(t, test.expectedImageUserValues.uid, *uid, "TestCase[%d]", j) 283 } 284 assert.Equal(t, test.expectedImageUserValues.username, username, "TestCase[%d]", j) 285 } 286 } 287 288 func TestToRuntimeProtocol(t *testing.T) { 289 for _, test := range []struct { 290 name string 291 protocol string 292 expected runtimeapi.Protocol 293 }{ 294 { 295 name: "TCP protocol", 296 protocol: "TCP", 297 expected: runtimeapi.Protocol_TCP, 298 }, 299 { 300 name: "UDP protocol", 301 protocol: "UDP", 302 expected: runtimeapi.Protocol_UDP, 303 }, 304 { 305 name: "SCTP protocol", 306 protocol: "SCTP", 307 expected: runtimeapi.Protocol_SCTP, 308 }, 309 { 310 name: "unknown protocol", 311 protocol: "unknown", 312 expected: runtimeapi.Protocol_TCP, 313 }, 314 } { 315 t.Run(test.name, func(t *testing.T) { 316 if result := toRuntimeProtocol(v1.Protocol(test.protocol)); result != test.expected { 317 t.Errorf("expected %d but got %d", test.expected, result) 318 } 319 }) 320 } 321 } 322 323 func TestToKubeContainerState(t *testing.T) { 324 for _, test := range []struct { 325 name string 326 state int32 327 expected kubecontainer.State 328 }{ 329 { 330 name: "container created", 331 state: 0, 332 expected: kubecontainer.ContainerStateCreated, 333 }, 334 { 335 name: "container running", 336 state: 1, 337 expected: kubecontainer.ContainerStateRunning, 338 }, 339 { 340 name: "container exited", 341 state: 2, 342 expected: kubecontainer.ContainerStateExited, 343 }, 344 { 345 name: "unknown state", 346 state: 3, 347 expected: kubecontainer.ContainerStateUnknown, 348 }, 349 { 350 name: "not supported state", 351 state: 4, 352 expected: kubecontainer.ContainerStateUnknown, 353 }, 354 } { 355 t.Run(test.name, func(t *testing.T) { 356 if result := toKubeContainerState(runtimeapi.ContainerState(test.state)); result != test.expected { 357 t.Errorf("expected %s but got %s", test.expected, result) 358 } 359 }) 360 } 361 }