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 }