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  }