github.com/kubewharf/katalyst-core@v0.5.3/pkg/agent/sysadvisor/metacache/metacache_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 metacache 18 19 import ( 20 "fmt" 21 "os" 22 "reflect" 23 "testing" 24 "time" 25 26 "github.com/stretchr/testify/require" 27 "k8s.io/kubernetes/pkg/kubelet/checkpointmanager" 28 29 borweinconsts "github.com/kubewharf/katalyst-core/pkg/agent/sysadvisor/plugin/inference/models/borwein/consts" 30 "github.com/kubewharf/katalyst-core/pkg/agent/sysadvisor/types" 31 "github.com/kubewharf/katalyst-core/pkg/metrics" 32 ) 33 34 func TestMetaCacheImp_GetFilteredInferenceResult(t *testing.T) { 35 t.Parallel() 36 type fields struct { 37 emitter metrics.MetricEmitter 38 modelToResult map[string]interface{} 39 } 40 type args struct { 41 filterFunc func(result interface{}) (interface{}, error) 42 modelName string 43 } 44 tests := []struct { 45 name string 46 fields fields 47 args args 48 want interface{} 49 wantErr bool 50 }{ 51 { 52 name: "test without filter", 53 fields: fields{ 54 emitter: metrics.DummyMetrics{}, 55 modelToResult: map[string]interface{}{ 56 borweinconsts.ModelNameBorwein: []int{1, 2, 3}, 57 }, 58 }, 59 args: args{ 60 modelName: borweinconsts.ModelNameBorwein, 61 }, 62 want: []int{1, 2, 3}, 63 wantErr: false, 64 }, 65 { 66 name: "test with filter", 67 fields: fields{ 68 emitter: metrics.DummyMetrics{}, 69 modelToResult: map[string]interface{}{ 70 borweinconsts.ModelNameBorwein: []int{1, 2, 3}, 71 }, 72 }, 73 args: args{ 74 filterFunc: func(result interface{}) (interface{}, error) { 75 parsedResult, ok := result.([]int) 76 77 if !ok { 78 return nil, fmt.Errorf("invalid result") 79 } 80 81 filteredResult := []int{} 82 83 for _, result := range parsedResult { 84 if result < 3 { 85 filteredResult = append(filteredResult, result) 86 } 87 } 88 89 return filteredResult, nil 90 }, 91 modelName: borweinconsts.ModelNameBorwein, 92 }, 93 want: []int{1, 2}, 94 wantErr: false, 95 }, 96 { 97 name: "test with invalid result type", 98 fields: fields{ 99 emitter: metrics.DummyMetrics{}, 100 modelToResult: map[string]interface{}{ 101 borweinconsts.ModelNameBorwein: []string{"1", "2", "3"}, 102 }, 103 }, 104 args: args{ 105 filterFunc: func(result interface{}) (interface{}, error) { 106 parsedResult, ok := result.([]int) 107 108 if !ok { 109 return nil, fmt.Errorf("invalid result") 110 } 111 112 filteredResult := []int{} 113 114 for _, result := range parsedResult { 115 if result < 3 { 116 filteredResult = append(filteredResult, result) 117 } 118 } 119 120 return filteredResult, nil 121 }, 122 modelName: borweinconsts.ModelNameBorwein, 123 }, 124 want: nil, 125 wantErr: true, 126 }, 127 } 128 for _, tt := range tests { 129 tt := tt 130 t.Run(tt.name, func(t *testing.T) { 131 t.Parallel() 132 mc := &MetaCacheImp{ 133 emitter: tt.fields.emitter, 134 modelToResult: tt.fields.modelToResult, 135 } 136 got, err := mc.GetFilteredInferenceResult(tt.args.filterFunc, tt.args.modelName) 137 if (err != nil) != tt.wantErr { 138 t.Errorf("MetaCacheImp.GetFilteredInferenceResult() error = %v, wantErr %v", err, tt.wantErr) 139 return 140 } 141 if !reflect.DeepEqual(got, tt.want) { 142 t.Errorf("MetaCacheImp.GetFilteredInferenceResult() = %v, want %v", got, tt.want) 143 } 144 }) 145 } 146 } 147 148 func TestMetaCacheImp_GetInferenceResult(t *testing.T) { 149 t.Parallel() 150 type fields struct { 151 emitter metrics.MetricEmitter 152 modelToResult map[string]interface{} 153 } 154 type args struct { 155 modelName string 156 } 157 tests := []struct { 158 name string 159 fields fields 160 args args 161 want interface{} 162 wantErr bool 163 }{ 164 { 165 name: "test get result directly", 166 fields: fields{ 167 emitter: metrics.DummyMetrics{}, 168 modelToResult: map[string]interface{}{ 169 borweinconsts.ModelNameBorwein: []int{1, 2, 3}, 170 }, 171 }, 172 args: args{ 173 modelName: borweinconsts.ModelNameBorwein, 174 }, 175 want: []int{1, 2, 3}, 176 wantErr: false, 177 }, 178 } 179 for _, tt := range tests { 180 tt := tt 181 t.Run(tt.name, func(t *testing.T) { 182 t.Parallel() 183 184 mc := &MetaCacheImp{ 185 emitter: tt.fields.emitter, 186 modelToResult: tt.fields.modelToResult, 187 } 188 got, err := mc.GetInferenceResult(tt.args.modelName) 189 if (err != nil) != tt.wantErr { 190 t.Errorf("MetaCacheImp.GetInferenceResult() error = %v, wantErr %v", err, tt.wantErr) 191 return 192 } 193 if !reflect.DeepEqual(got, tt.want) { 194 t.Errorf("MetaCacheImp.GetInferenceResult() = %v, want %v", got, tt.want) 195 } 196 }) 197 } 198 } 199 200 func TestMetaCacheImp_SetInferenceResult(t *testing.T) { 201 t.Parallel() 202 type fields struct { 203 emitter metrics.MetricEmitter 204 modelToResult map[string]interface{} 205 } 206 type args struct { 207 modelName string 208 result interface{} 209 } 210 tests := []struct { 211 name string 212 fields fields 213 args args 214 want interface{} 215 wantErr bool 216 }{ 217 { 218 name: "get after set", 219 fields: fields{ 220 emitter: metrics.DummyMetrics{}, 221 modelToResult: make(map[string]interface{}), 222 }, 223 args: args{ 224 modelName: borweinconsts.ModelNameBorwein, 225 result: []int{1, 2, 3}, 226 }, 227 want: []int{1, 2, 3}, 228 wantErr: false, 229 }, 230 } 231 for _, tt := range tests { 232 tt := tt 233 t.Run(tt.name, func(t *testing.T) { 234 t.Parallel() 235 236 mc := &MetaCacheImp{ 237 emitter: tt.fields.emitter, 238 modelToResult: tt.fields.modelToResult, 239 } 240 241 if err := mc.SetInferenceResult(tt.args.modelName, tt.args.result); (err != nil) != tt.wantErr { 242 t.Errorf("MetaCacheImp.SetInferenceResult() error = %v, wantErr %v", err, tt.wantErr) 243 } 244 245 got, err := mc.GetInferenceResult(tt.args.modelName) 246 if (err != nil) != tt.wantErr { 247 t.Errorf("MetaCacheImp.GetInferenceResult() error = %v, wantErr %v", err, tt.wantErr) 248 return 249 } 250 if !reflect.DeepEqual(got, tt.want) { 251 t.Errorf("MetaCacheImp.GetInferenceResult() = %v, want %v", got, tt.want) 252 } 253 }) 254 } 255 } 256 257 func TestRangeAndDeleteContainerWithSafeTime(t *testing.T) { 258 t.Parallel() 259 260 testDir := "/tmp/mc-test-range-delete" 261 checkpointManager, err := checkpointmanager.NewCheckpointManager(testDir) 262 require.NoError(t, err, "failed to create checkpoint manager") 263 defer func() { 264 os.RemoveAll(testDir) 265 }() 266 267 mc := &MetaCacheImp{ 268 podEntries: map[string]types.ContainerEntries{}, 269 containerCreateTimestamp: map[string]int64{}, 270 checkpointManager: checkpointManager, 271 emitter: metrics.DummyMetrics{}, 272 checkpointName: "test-mc-range-delete", 273 } 274 ci := &types.ContainerInfo{ 275 PodUID: "pod1", 276 ContainerName: "c1", 277 } 278 require.NoError(t, mc.AddContainer("pod1", "c1", ci), "failed to add container") 279 280 require.NoError(t, mc.RangeAndDeleteContainer(func(containerInfo *types.ContainerInfo) bool { 281 return true 282 }, 0), "failed to range and delete container without safe time") 283 require.Equal(t, 0, len(mc.podEntries), "failed to delete container without safe time") 284 require.Equal(t, 0, len(mc.containerCreateTimestamp), "failed to delete container create timestamp without safe time") 285 286 require.NoError(t, mc.AddContainer("pod1", "c1", ci), "failed to add container") 287 require.NoError(t, mc.RangeAndDeleteContainer(func(containerInfo *types.ContainerInfo) bool { 288 return true 289 }, 1), "failed to skip range and delete container with safe time") 290 require.Equal(t, 1, len(mc.podEntries), "failed to protect container with safe time") 291 require.Equal(t, 1, len(mc.containerCreateTimestamp), "failed to protect container create timestamp with safe time") 292 293 require.NoError(t, mc.RangeAndDeleteContainer(func(containerInfo *types.ContainerInfo) bool { 294 return true 295 }, time.Now().UnixNano()), "failed to skip range and delete container with safe time") 296 require.Equal(t, 0, len(mc.podEntries), "failed to delete container before safe time") 297 require.Equal(t, 0, len(mc.containerCreateTimestamp), "failed to delete container create timestamp before safe time") 298 }