github.com/kubewharf/katalyst-core@v0.5.3/pkg/metaserver/external/cgroupid/manager_linux_test.go (about)

     1  //go:build linux
     2  // +build linux
     3  
     4  /*
     5  Copyright 2022 The Katalyst Authors.
     6  
     7  Licensed under the Apache License, Version 2.0 (the "License");
     8  you may not use this file except in compliance with the License.
     9  You may obtain a copy of the License at
    10  
    11      http://www.apache.org/licenses/LICENSE-2.0
    12  
    13  Unless required by applicable law or agreed to in writing, software
    14  distributed under the License is distributed on an "AS IS" BASIS,
    15  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    16  See the License for the specific language governing permissions and
    17  limitations under the License.
    18  */
    19  
    20  package cgroupid
    21  
    22  import (
    23  	"reflect"
    24  	"sort"
    25  	"testing"
    26  	"time"
    27  
    28  	"github.com/stretchr/testify/assert"
    29  	v1 "k8s.io/api/core/v1"
    30  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    31  	"k8s.io/apimachinery/pkg/types"
    32  	"k8s.io/apimachinery/pkg/util/sets"
    33  
    34  	"github.com/kubewharf/katalyst-core/pkg/metaserver/agent/pod"
    35  )
    36  
    37  var (
    38  	podFetcher        = makePodFetcher(makePodList())
    39  	podUIDList        = []string{"uid-1", "uid-2", "uid-3", "uid-4"}
    40  	containerIDList   = []string{"container-id-1", "container-id-2", "container-id-3", "container-id-4", "container-id-5", "container-id-6"}
    41  	containerNameList = []string{"container-name-1", "container-name-2", "container-name-3", "container-name-4", "container-name-5", "container-name-6"}
    42  	cgIDList          = []uint64{1, 2, 3, 4, 5, 6}
    43  )
    44  
    45  func TestGetCgroupIDForContainer(t *testing.T) {
    46  	t.Parallel()
    47  
    48  	cgroupIDManager := NewCgroupIDManager(podFetcher).(*cgroupIDManagerImpl)
    49  	assert.NotNil(t, cgroupIDManager)
    50  
    51  	cgroupIDManager.setCgroupID(podUIDList[0], containerIDList[0], cgIDList[0])
    52  	cgroupIDManager.setCgroupID(podUIDList[1], containerIDList[1], cgIDList[1])
    53  
    54  	tests := []struct {
    55  		name        string
    56  		podUID      string
    57  		containerID string
    58  		want        uint64
    59  	}{
    60  		{
    61  			name:        "get cgID for container 1",
    62  			podUID:      podUIDList[0],
    63  			containerID: containerIDList[0],
    64  			want:        cgIDList[0],
    65  		},
    66  		{
    67  			name:        "get cgID for container 2",
    68  			podUID:      podUIDList[1],
    69  			containerID: containerIDList[1],
    70  			want:        cgIDList[1],
    71  		},
    72  	}
    73  
    74  	for _, tt := range tests {
    75  		tt := tt
    76  		t.Run(tt.name, func(t *testing.T) {
    77  			t.Parallel()
    78  			cgID, err := cgroupIDManager.GetCgroupIDForContainer(tt.podUID, tt.containerID)
    79  			assert.NoError(t, err)
    80  			assert.Equal(t, tt.want, cgID)
    81  		})
    82  	}
    83  }
    84  
    85  func TestListCgroupIDsForPod(t *testing.T) {
    86  	t.Parallel()
    87  
    88  	cgroupIDManager := NewCgroupIDManager(podFetcher).(*cgroupIDManagerImpl)
    89  	assert.NotNil(t, cgroupIDManager)
    90  
    91  	cgroupIDManager.setCgroupID(podUIDList[0], containerIDList[0], cgIDList[0])
    92  	cgroupIDManager.setCgroupID(podUIDList[1], containerIDList[1], cgIDList[1])
    93  	cgroupIDManager.setCgroupID(podUIDList[1], containerIDList[2], cgIDList[2])
    94  
    95  	tests := []struct {
    96  		name   string
    97  		podUID string
    98  		want   []uint64
    99  	}{
   100  		{
   101  			name:   "get cgID for pod 1",
   102  			podUID: podUIDList[0],
   103  			want:   []uint64{cgIDList[0]},
   104  		},
   105  		{
   106  			name:   "get cgID for pod 2",
   107  			podUID: podUIDList[1],
   108  			want:   []uint64{cgIDList[1], cgIDList[2]},
   109  		},
   110  	}
   111  
   112  	for _, tt := range tests {
   113  		tt := tt
   114  		t.Run(tt.name, func(t *testing.T) {
   115  			t.Parallel()
   116  
   117  			cgIDs, err := cgroupIDManager.ListCgroupIDsForPod(tt.podUID)
   118  			assert.NoError(t, err)
   119  			sort.Slice(tt.want, func(i, j int) bool { return tt.want[i] < tt.want[j] })
   120  			sort.Slice(cgIDs, func(i, j int) bool { return cgIDs[i] < cgIDs[j] })
   121  			assert.True(t, reflect.DeepEqual(tt.want, cgIDs))
   122  		})
   123  	}
   124  }
   125  
   126  func TestGetAbsentContainers(t *testing.T) {
   127  	t.Parallel()
   128  
   129  	cgroupIDManager := NewCgroupIDManager(podFetcher).(*cgroupIDManagerImpl)
   130  	assert.NotNil(t, cgroupIDManager)
   131  
   132  	cgroupIDManager.setCgroupID(podUIDList[0], containerIDList[0], cgIDList[0])
   133  	cgroupIDManager.setCgroupID(podUIDList[1], containerIDList[1], cgIDList[1])
   134  	cgroupIDManager.setCgroupID(podUIDList[1], containerIDList[2], cgIDList[2])
   135  
   136  	tests := []struct {
   137  		name    string
   138  		podList []*v1.Pod
   139  		want    map[string]sets.String
   140  	}{
   141  		{
   142  			name:    "get absent containers",
   143  			podList: makePodList(),
   144  			want: map[string]sets.String{
   145  				podUIDList[1]: sets.NewString(containerIDList[3]),
   146  				podUIDList[2]: sets.NewString(containerIDList[4]),
   147  			},
   148  		},
   149  	}
   150  
   151  	for _, tt := range tests {
   152  		tt := tt
   153  		t.Run(tt.name, func(t *testing.T) {
   154  			t.Parallel()
   155  
   156  			gotAbsentContainers := cgroupIDManager.getAbsentContainers(tt.podList)
   157  			assert.Equal(t, len(tt.want), len(gotAbsentContainers))
   158  			for wantPodUID, wantContainerSet := range tt.want {
   159  				gotContainerSet, ok := gotAbsentContainers[wantPodUID]
   160  				assert.True(t, ok)
   161  				assert.True(t, wantContainerSet.Equal(gotContainerSet))
   162  			}
   163  		})
   164  	}
   165  }
   166  
   167  func TestClearResidualPodsInCache(t *testing.T) {
   168  	t.Parallel()
   169  
   170  	cgroupIDManager := NewCgroupIDManager(podFetcher).(*cgroupIDManagerImpl)
   171  	assert.NotNil(t, cgroupIDManager)
   172  
   173  	cgroupIDManager.setCgroupID(podUIDList[0], containerIDList[0], cgIDList[0])
   174  	cgroupIDManager.setCgroupID(podUIDList[1], containerIDList[1], cgIDList[1])
   175  	cgroupIDManager.setCgroupID(podUIDList[1], containerIDList[2], cgIDList[2])
   176  	cgroupIDManager.setCgroupID(podUIDList[3], containerIDList[5], cgIDList[5])
   177  
   178  	tests := []struct {
   179  		name    string
   180  		podList []*v1.Pod
   181  		want    map[string]map[string]uint64
   182  	}{
   183  		{
   184  			name:    "clear residual pods in cache",
   185  			podList: makePodList(),
   186  			want: map[string]map[string]uint64{
   187  				podUIDList[0]: {
   188  					containerIDList[0]: cgIDList[0],
   189  				},
   190  				podUIDList[1]: {
   191  					containerIDList[1]: cgIDList[1],
   192  					containerIDList[2]: cgIDList[2],
   193  				},
   194  			},
   195  		},
   196  	}
   197  
   198  	for _, tt := range tests {
   199  		tt := tt
   200  		t.Run(tt.name, func(t *testing.T) {
   201  			t.Parallel()
   202  			for i := 0; time.Duration(i)*cgroupIDManager.reconcilePeriod < maxResidualTime; i++ {
   203  				cgroupIDManager.clearResidualPodsInCache(tt.podList)
   204  			}
   205  
   206  			assert.Equal(t, len(tt.want), len(cgroupIDManager.podCgroupIDCache))
   207  			for wantPodUID, wantContainerMap := range tt.want {
   208  				cgroupIDManager.Lock()
   209  				gotContainerMap, ok := cgroupIDManager.podCgroupIDCache[wantPodUID]
   210  
   211  				assert.True(t, ok)
   212  				assert.Equal(t, len(wantContainerMap), len(gotContainerMap))
   213  				for wantContainerID, wantCgID := range wantContainerMap {
   214  					gotCgID, ok := wantContainerMap[wantContainerID]
   215  					assert.True(t, ok)
   216  					assert.Equal(t, wantCgID, gotCgID)
   217  				}
   218  				cgroupIDManager.Unlock()
   219  			}
   220  		})
   221  	}
   222  }
   223  
   224  func makePodFetcher(podList []*v1.Pod) pod.PodFetcher {
   225  	podFetcher := pod.PodFetcherStub{}
   226  	if len(podList) > 0 {
   227  		podFetcher.PodList = podList
   228  	}
   229  	return &podFetcher
   230  }
   231  
   232  func makePodList() []*v1.Pod {
   233  	return []*v1.Pod{
   234  		{
   235  			ObjectMeta: metav1.ObjectMeta{
   236  				UID: types.UID(podUIDList[0]),
   237  			},
   238  			Spec: v1.PodSpec{
   239  				Containers: []v1.Container{
   240  					{
   241  						Name: containerNameList[0],
   242  					},
   243  				},
   244  			},
   245  			Status: v1.PodStatus{
   246  				ContainerStatuses: []v1.ContainerStatus{
   247  					{
   248  						Name:        containerNameList[0],
   249  						ContainerID: containerIDList[0],
   250  					},
   251  				},
   252  			},
   253  		},
   254  		{
   255  			ObjectMeta: metav1.ObjectMeta{
   256  				UID: types.UID(podUIDList[1]),
   257  			},
   258  			Spec: v1.PodSpec{
   259  				Containers: []v1.Container{
   260  					{
   261  						Name: containerNameList[1],
   262  					},
   263  					{
   264  						Name: containerNameList[2],
   265  					},
   266  					{
   267  						Name: containerNameList[3],
   268  					},
   269  				},
   270  			},
   271  			Status: v1.PodStatus{
   272  				ContainerStatuses: []v1.ContainerStatus{
   273  					{
   274  						Name:        containerNameList[1],
   275  						ContainerID: containerIDList[1],
   276  					},
   277  					{
   278  						Name:        containerNameList[2],
   279  						ContainerID: containerIDList[2],
   280  					},
   281  					{
   282  						Name:        containerNameList[3],
   283  						ContainerID: containerIDList[3],
   284  					},
   285  				},
   286  			},
   287  		},
   288  		{
   289  			ObjectMeta: metav1.ObjectMeta{
   290  				UID: types.UID(podUIDList[2]),
   291  			},
   292  			Spec: v1.PodSpec{
   293  				Containers: []v1.Container{
   294  					{
   295  						Name: containerNameList[4],
   296  					},
   297  				},
   298  			},
   299  			Status: v1.PodStatus{
   300  				ContainerStatuses: []v1.ContainerStatus{
   301  					{
   302  						Name:        containerNameList[4],
   303  						ContainerID: containerIDList[4],
   304  					},
   305  				},
   306  			},
   307  		},
   308  	}
   309  }