github.com/kubewharf/katalyst-core@v0.5.3/pkg/controller/resource-recommend/oom/oom_recorder_test.go (about)

     1  /*
     2  Copyright 2022 The Katalyst 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 oom
    18  
    19  import (
    20  	"context"
    21  	"testing"
    22  	"time"
    23  
    24  	v1 "k8s.io/api/core/v1"
    25  	"k8s.io/apimachinery/pkg/api/resource"
    26  	"sigs.k8s.io/controller-runtime/pkg/client/fake"
    27  )
    28  
    29  func TestCleanOOMRecord(t *testing.T) {
    30  	oomRecordsList := []PodOOMRecorder{
    31  		{
    32  			OOMRecordMaxNumber: 4,
    33  			cache: []OOMRecord{
    34  				{
    35  					OOMAt: time.Now().Add(-140 * time.Hour),
    36  				},
    37  				{
    38  					OOMAt: time.Now().Add(-150 * time.Hour),
    39  				},
    40  				{
    41  					OOMAt: time.Now().Add(-150 * time.Hour),
    42  				},
    43  				{
    44  					OOMAt: time.Now().Add(-150 * time.Hour),
    45  				},
    46  				{
    47  					OOMAt: time.Now().Add(-150 * time.Hour),
    48  				},
    49  				{
    50  					OOMAt: time.Now().Add(-160 * time.Hour),
    51  				},
    52  				{
    53  					OOMAt: time.Now().Add(-170 * time.Hour),
    54  				},
    55  				{
    56  					OOMAt: time.Now().Add(-180 * time.Hour),
    57  				},
    58  				{
    59  					OOMAt: time.Now().Add(-190 * time.Hour),
    60  				},
    61  			},
    62  		},
    63  		{
    64  			OOMRecordMaxNumber: 4,
    65  			cache: []OOMRecord{
    66  				{
    67  					OOMAt: time.Now().Add(-150 * time.Hour),
    68  				},
    69  				{
    70  					OOMAt: time.Now().Add(-140 * time.Hour),
    71  				},
    72  				{
    73  					OOMAt: time.Now().Add(-130 * time.Hour),
    74  				},
    75  				{
    76  					OOMAt: time.Now().Add(-120 * time.Hour),
    77  				},
    78  				{
    79  					OOMAt: time.Now().Add(-110 * time.Hour),
    80  				},
    81  			},
    82  		},
    83  		{
    84  			OOMRecordMaxNumber: 4,
    85  			cache: []OOMRecord{
    86  				{
    87  					OOMAt: time.Now().Add(-170 * time.Hour),
    88  				},
    89  				{
    90  					OOMAt: time.Now().Add(-180 * time.Hour),
    91  				},
    92  				{
    93  					OOMAt: time.Now().Add(-190 * time.Hour),
    94  				},
    95  				{
    96  					OOMAt: time.Now().Add(-190 * time.Hour),
    97  				},
    98  				{
    99  					OOMAt: time.Now().Add(-200 * time.Hour),
   100  				},
   101  				{
   102  					OOMAt: time.Now().Add(-210 * time.Hour),
   103  				},
   104  			},
   105  		},
   106  		{
   107  			OOMRecordMaxNumber: 4,
   108  			cache: []OOMRecord{
   109  				{
   110  					OOMAt: time.Now().Add(-160 * time.Hour),
   111  				},
   112  				{
   113  					OOMAt: time.Now().Add(-170 * time.Hour),
   114  				},
   115  				{
   116  					OOMAt: time.Now().Add(-180 * time.Hour),
   117  				},
   118  			},
   119  		},
   120  		{
   121  			OOMRecordMaxNumber: 4,
   122  			cache: []OOMRecord{
   123  				{
   124  					OOMAt: time.Now().Add(-170 * time.Hour),
   125  				},
   126  				{
   127  					OOMAt: time.Now().Add(-180 * time.Hour),
   128  				},
   129  				{
   130  					OOMAt: time.Now().Add(-190 * time.Hour),
   131  				},
   132  			},
   133  		},
   134  		{
   135  			OOMRecordMaxNumber: 4,
   136  			cache: []OOMRecord{
   137  				{
   138  					OOMAt: time.Now().Add(-160 * time.Hour),
   139  				},
   140  				{
   141  					OOMAt: time.Now().Add(-150 * time.Hour),
   142  				},
   143  				{
   144  					OOMAt: time.Now().Add(-140 * time.Hour),
   145  				},
   146  			},
   147  		},
   148  		{
   149  			OOMRecordMaxNumber: 4,
   150  			cache:              []OOMRecord{},
   151  		},
   152  	}
   153  	for index := range oomRecordsList {
   154  		splitTimePoints := time.Now().Add(-DataRetentionHour * time.Hour)
   155  		oomRecordsList[index].cleanOOMRecord()
   156  		if len(oomRecordsList[index].cache) > oomRecordsList[index].OOMRecordMaxNumber {
   157  			t.Errorf("Expected oomRecordsList length to be less than or equal to %d, but it is actually %d",
   158  				oomRecordsList[index].OOMRecordMaxNumber, len(oomRecordsList[index].cache))
   159  		}
   160  		for _, record := range oomRecordsList[index].cache {
   161  			if record.OOMAt.Before(splitTimePoints) {
   162  				t.Errorf("Expected oomAt to be greater than %v, but it is actually %v", splitTimePoints, record.OOMAt)
   163  			}
   164  		}
   165  	}
   166  }
   167  
   168  func TestListOOMRecordsFromConfigmap(t *testing.T) {
   169  	dummyClient := fake.NewClientBuilder().WithObjects(&v1.ConfigMap{}).Build()
   170  	dummyPodOOMRecorder := PodOOMRecorder{
   171  		Client: dummyClient,
   172  	}
   173  	oomRecords, _ := dummyPodOOMRecorder.ListOOMRecordsFromConfigmap()
   174  	if len(oomRecords) > 0 {
   175  		t.Errorf("Expected oomRecords length is zero, but actual oomRecords length is %v", len(oomRecords))
   176  	}
   177  	oomConfigMap := &v1.ConfigMap{
   178  		Data: map[string]string{
   179  			ConfigMapDataOOMRecord: `[{"Namespace":"dummyNamespace","Pod":"dummyPod","Container":"dummyContainer","Memory":"600Mi","OOMAt":"2023-08-07T16:45:50+08:00"},{"Namespace":"dummyNamespace","Pod":"dummyPod","Container":"dummyContainer","Memory":"600Mi","OOMAt":"2023-08-07T16:46:07+08:00"}]`,
   180  		},
   181  	}
   182  	oomConfigMap.SetName(ConfigMapOOMRecordName)
   183  	oomConfigMap.SetNamespace(ConfigMapOOMRecordNameSpace)
   184  	dummyPodOOMRecorder.Client.Create(context.TODO(), oomConfigMap)
   185  	oomRecords, err := dummyPodOOMRecorder.ListOOMRecordsFromConfigmap()
   186  	if err != nil || len(oomRecords) != 2 {
   187  		t.Errorf("Expected oomRecords length is 2 and err is nil, but actual oomRecords length is %v and err is %v", len(oomRecords), err)
   188  	}
   189  }
   190  
   191  func TestUpdateOOMRecordCache(t *testing.T) {
   192  	now := time.Now()
   193  	dummyClient := fake.NewClientBuilder().WithObjects(&v1.ConfigMap{}).Build()
   194  	podOOMRecorderList := []PodOOMRecorder{
   195  		{
   196  			Client: dummyClient,
   197  			cache: []OOMRecord{
   198  				{
   199  					Namespace: "dummyNamespace1",
   200  					Pod:       "dummyPod1",
   201  					Container: "dummyContainer1",
   202  					Memory:    resource.MustParse("6Gi"),
   203  					OOMAt:     now,
   204  				},
   205  			},
   206  		},
   207  		{
   208  			Client: dummyClient,
   209  			cache: []OOMRecord{
   210  				{
   211  					Namespace: "dummyNamespace",
   212  					Pod:       "dummyPod",
   213  					Container: "dummyContainer",
   214  					Memory:    resource.MustParse("6Gi"),
   215  					OOMAt:     now,
   216  				},
   217  			},
   218  		},
   219  		{
   220  			Client: dummyClient,
   221  			cache: []OOMRecord{
   222  				{
   223  					Namespace: "dummyNamespace",
   224  					Pod:       "dummyPod",
   225  					Container: "dummyContainer",
   226  					Memory:    resource.MustParse("6Gi"),
   227  					OOMAt:     now.Add(1 * time.Hour),
   228  				},
   229  			},
   230  		},
   231  		{
   232  			Client: dummyClient,
   233  			cache: []OOMRecord{
   234  				{
   235  					Namespace: "dummyNamespace",
   236  					Pod:       "dummyPod",
   237  					Container: "dummyContainer",
   238  					Memory:    resource.MustParse("7Gi"),
   239  					OOMAt:     now.Add(1 * time.Hour),
   240  				},
   241  			},
   242  		},
   243  		{
   244  			Client: dummyClient,
   245  			cache: []OOMRecord{
   246  				{
   247  					Namespace: "dummyNamespace",
   248  					Pod:       "dummyPod",
   249  					Container: "dummyContainer",
   250  					Memory:    resource.MustParse("5Gi"),
   251  					OOMAt:     now.Add(1 * time.Hour),
   252  				},
   253  			},
   254  		},
   255  	}
   256  	oomRecord := OOMRecord{
   257  		Namespace: "dummyNamespace",
   258  		Pod:       "dummyPod",
   259  		Container: "dummyContainer",
   260  		Memory:    resource.MustParse("6Gi"),
   261  		OOMAt:     now,
   262  	}
   263  	resultList := []bool{true, false, true, false, true}
   264  	for index := range podOOMRecorderList {
   265  		isUpdated := podOOMRecorderList[index].updateOOMRecordCache(oomRecord)
   266  		if isUpdated != resultList[index] {
   267  			t.Errorf("Expected isUpdated %v, but it is actually %v", resultList[index], isUpdated)
   268  		}
   269  	}
   270  }
   271  
   272  func TestUpdateOOMRecordConfigMap(t *testing.T) {
   273  	dummyClient := fake.NewClientBuilder().WithObjects(&v1.ConfigMap{}).Build()
   274  	oomConfigMap := &v1.ConfigMap{
   275  		Data: map[string]string{
   276  			ConfigMapDataOOMRecord: `[]`,
   277  		},
   278  	}
   279  	oomConfigMap.SetName(ConfigMapOOMRecordName)
   280  	oomConfigMap.SetNamespace(ConfigMapOOMRecordNameSpace)
   281  	dummyPodOOMRecorder := PodOOMRecorder{
   282  		Client: dummyClient,
   283  		cache: []OOMRecord{
   284  			{
   285  				Namespace: "dummyNamespace",
   286  				Pod:       "dummyPod",
   287  				Container: "dummyContainer",
   288  				Memory:    resource.MustParse("600Mi"),
   289  				OOMAt:     time.Date(2012, time.March, 4, 0, 0, 0, 0, time.UTC),
   290  			},
   291  		},
   292  	}
   293  	err := dummyPodOOMRecorder.updateOOMRecordConfigMap()
   294  	if err != nil {
   295  		t.Errorf("Expected the configMap was successfully created,but actually an error:%v occurred.", err)
   296  	}
   297  	oomRecordList, _ := dummyPodOOMRecorder.ListOOMRecordsFromConfigmap()
   298  	for index := range oomRecordList {
   299  		if dummyPodOOMRecorder.cache[index] != oomRecordList[index] {
   300  			t.Errorf("Expected OOMRecord value is %v, actually OOMRecord value is %v",
   301  				dummyPodOOMRecorder.cache[index], oomRecordList[index])
   302  		}
   303  	}
   304  
   305  	dummyPodOOMRecorder.Client.DeleteAllOf(context.TODO(), oomConfigMap)
   306  	dummyPodOOMRecorder.Client.Create(context.TODO(), oomConfigMap)
   307  	err = dummyPodOOMRecorder.updateOOMRecordConfigMap()
   308  	if err != nil {
   309  		t.Errorf("Expected the configMap was successfully updated,but actually an error:%v occurred.", err)
   310  	}
   311  	oomRecordList, _ = dummyPodOOMRecorder.ListOOMRecordsFromConfigmap()
   312  	for index := range oomRecordList {
   313  		if dummyPodOOMRecorder.cache[index] != oomRecordList[index] {
   314  			t.Errorf("Expected OOMRecord value is %v, actually OOMRecord value is %v",
   315  				dummyPodOOMRecorder.cache[index], oomRecordList[index])
   316  		}
   317  	}
   318  }