k8s.io/kubernetes@v1.29.3/pkg/scheduler/internal/heap/heap_test.go (about) 1 /* 2 Copyright 2018 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 // This file was copied from client-go/tools/cache/heap.go and modified 18 // for our non thread-safe heap 19 20 package heap 21 22 import ( 23 "testing" 24 ) 25 26 func testHeapObjectKeyFunc(obj interface{}) (string, error) { 27 return obj.(testHeapObject).name, nil 28 } 29 30 type testHeapObject struct { 31 name string 32 val interface{} 33 } 34 35 type testMetricRecorder int 36 37 func (tmr *testMetricRecorder) Inc() { 38 if tmr != nil { 39 *tmr++ 40 } 41 } 42 43 func (tmr *testMetricRecorder) Dec() { 44 if tmr != nil { 45 *tmr-- 46 } 47 } 48 49 func (tmr *testMetricRecorder) Clear() { 50 if tmr != nil { 51 *tmr = 0 52 } 53 } 54 55 func mkHeapObj(name string, val interface{}) testHeapObject { 56 return testHeapObject{name: name, val: val} 57 } 58 59 func compareInts(val1 interface{}, val2 interface{}) bool { 60 first := val1.(testHeapObject).val.(int) 61 second := val2.(testHeapObject).val.(int) 62 return first < second 63 } 64 65 // TestHeapBasic tests Heap invariant 66 func TestHeapBasic(t *testing.T) { 67 h := New(testHeapObjectKeyFunc, compareInts) 68 const amount = 500 69 var i int 70 71 // empty queue 72 if item := h.Peek(); item != nil { 73 t.Errorf("expected nil object but got %v", item) 74 } 75 76 for i = amount; i > 0; i-- { 77 h.Add(mkHeapObj(string([]rune{'a', rune(i)}), i)) 78 // Retrieve head without removing it 79 head := h.Peek() 80 if e, a := i, head.(testHeapObject).val; a != e { 81 t.Errorf("expected %d, got %d", e, a) 82 } 83 } 84 85 // Make sure that the numbers are popped in ascending order. 86 prevNum := 0 87 for i := 0; i < amount; i++ { 88 obj, err := h.Pop() 89 num := obj.(testHeapObject).val.(int) 90 // All the items must be sorted. 91 if err != nil || prevNum > num { 92 t.Errorf("got %v out of order, last was %v", obj, prevNum) 93 } 94 prevNum = num 95 } 96 } 97 98 // Tests Heap.Add and ensures that heap invariant is preserved after adding items. 99 func TestHeap_Add(t *testing.T) { 100 h := New(testHeapObjectKeyFunc, compareInts) 101 h.Add(mkHeapObj("foo", 10)) 102 h.Add(mkHeapObj("bar", 1)) 103 h.Add(mkHeapObj("baz", 11)) 104 h.Add(mkHeapObj("zab", 30)) 105 h.Add(mkHeapObj("foo", 13)) // This updates "foo". 106 107 item, err := h.Pop() 108 if e, a := 1, item.(testHeapObject).val; err != nil || a != e { 109 t.Fatalf("expected %d, got %d", e, a) 110 } 111 item, err = h.Pop() 112 if e, a := 11, item.(testHeapObject).val; err != nil || a != e { 113 t.Fatalf("expected %d, got %d", e, a) 114 } 115 h.Delete(mkHeapObj("baz", 11)) // Nothing is deleted. 116 h.Add(mkHeapObj("foo", 14)) // foo is updated. 117 item, err = h.Pop() 118 if e, a := 14, item.(testHeapObject).val; err != nil || a != e { 119 t.Fatalf("expected %d, got %d", e, a) 120 } 121 item, err = h.Pop() 122 if e, a := 30, item.(testHeapObject).val; err != nil || a != e { 123 t.Fatalf("expected %d, got %d", e, a) 124 } 125 } 126 127 // TestHeap_Delete tests Heap.Delete and ensures that heap invariant is 128 // preserved after deleting items. 129 func TestHeap_Delete(t *testing.T) { 130 h := New(testHeapObjectKeyFunc, compareInts) 131 h.Add(mkHeapObj("foo", 10)) 132 h.Add(mkHeapObj("bar", 1)) 133 h.Add(mkHeapObj("bal", 31)) 134 h.Add(mkHeapObj("baz", 11)) 135 136 // Delete head. Delete should work with "key" and doesn't care about the value. 137 if err := h.Delete(mkHeapObj("bar", 200)); err != nil { 138 t.Fatalf("Failed to delete head.") 139 } 140 item, err := h.Pop() 141 if e, a := 10, item.(testHeapObject).val; err != nil || a != e { 142 t.Fatalf("expected %d, got %d", e, a) 143 } 144 h.Add(mkHeapObj("zab", 30)) 145 h.Add(mkHeapObj("faz", 30)) 146 len := h.data.Len() 147 // Delete non-existing item. 148 if err = h.Delete(mkHeapObj("non-existent", 10)); err == nil || len != h.data.Len() { 149 t.Fatalf("Didn't expect any item removal") 150 } 151 // Delete tail. 152 if err = h.Delete(mkHeapObj("bal", 31)); err != nil { 153 t.Fatalf("Failed to delete tail.") 154 } 155 // Delete one of the items with value 30. 156 if err = h.Delete(mkHeapObj("zab", 30)); err != nil { 157 t.Fatalf("Failed to delete item.") 158 } 159 item, err = h.Pop() 160 if e, a := 11, item.(testHeapObject).val; err != nil || a != e { 161 t.Fatalf("expected %d, got %d", e, a) 162 } 163 item, err = h.Pop() 164 if e, a := 30, item.(testHeapObject).val; err != nil || a != e { 165 t.Fatalf("expected %d, got %d", e, a) 166 } 167 if h.data.Len() != 0 { 168 t.Fatalf("expected an empty heap.") 169 } 170 } 171 172 // TestHeap_Update tests Heap.Update and ensures that heap invariant is 173 // preserved after adding items. 174 func TestHeap_Update(t *testing.T) { 175 h := New(testHeapObjectKeyFunc, compareInts) 176 h.Add(mkHeapObj("foo", 10)) 177 h.Add(mkHeapObj("bar", 1)) 178 h.Add(mkHeapObj("bal", 31)) 179 h.Add(mkHeapObj("baz", 11)) 180 181 // Update an item to a value that should push it to the head. 182 h.Update(mkHeapObj("baz", 0)) 183 if h.data.queue[0] != "baz" || h.data.items["baz"].index != 0 { 184 t.Fatalf("expected baz to be at the head") 185 } 186 item, err := h.Pop() 187 if e, a := 0, item.(testHeapObject).val; err != nil || a != e { 188 t.Fatalf("expected %d, got %d", e, a) 189 } 190 // Update bar to push it farther back in the queue. 191 h.Update(mkHeapObj("bar", 100)) 192 if h.data.queue[0] != "foo" || h.data.items["foo"].index != 0 { 193 t.Fatalf("expected foo to be at the head") 194 } 195 } 196 197 // TestHeap_Get tests Heap.Get. 198 func TestHeap_Get(t *testing.T) { 199 h := New(testHeapObjectKeyFunc, compareInts) 200 h.Add(mkHeapObj("foo", 10)) 201 h.Add(mkHeapObj("bar", 1)) 202 h.Add(mkHeapObj("bal", 31)) 203 h.Add(mkHeapObj("baz", 11)) 204 205 // Get works with the key. 206 obj, exists, err := h.Get(mkHeapObj("baz", 0)) 207 if err != nil || exists == false || obj.(testHeapObject).val != 11 { 208 t.Fatalf("unexpected error in getting element") 209 } 210 // Get non-existing object. 211 _, exists, err = h.Get(mkHeapObj("non-existing", 0)) 212 if err != nil || exists { 213 t.Fatalf("didn't expect to get any object") 214 } 215 } 216 217 // TestHeap_GetByKey tests Heap.GetByKey and is very similar to TestHeap_Get. 218 func TestHeap_GetByKey(t *testing.T) { 219 h := New(testHeapObjectKeyFunc, compareInts) 220 h.Add(mkHeapObj("foo", 10)) 221 h.Add(mkHeapObj("bar", 1)) 222 h.Add(mkHeapObj("bal", 31)) 223 h.Add(mkHeapObj("baz", 11)) 224 225 obj, exists, err := h.GetByKey("baz") 226 if err != nil || !exists || obj.(testHeapObject).val != 11 { 227 t.Fatalf("unexpected error in getting element") 228 } 229 // Get non-existing object. 230 _, exists, err = h.GetByKey("non-existing") 231 if err != nil || exists { 232 t.Fatalf("didn't expect to get any object") 233 } 234 } 235 236 // TestHeap_List tests Heap.List function. 237 func TestHeap_List(t *testing.T) { 238 h := New(testHeapObjectKeyFunc, compareInts) 239 list := h.List() 240 if len(list) != 0 { 241 t.Errorf("expected an empty list") 242 } 243 244 items := map[string]int{ 245 "foo": 10, 246 "bar": 1, 247 "bal": 30, 248 "baz": 11, 249 "faz": 30, 250 } 251 for k, v := range items { 252 h.Add(mkHeapObj(k, v)) 253 } 254 list = h.List() 255 if len(list) != len(items) { 256 t.Errorf("expected %d items, got %d", len(items), len(list)) 257 } 258 for _, obj := range list { 259 heapObj := obj.(testHeapObject) 260 v, ok := items[heapObj.name] 261 if !ok || v != heapObj.val { 262 t.Errorf("unexpected item in the list: %v", heapObj) 263 } 264 } 265 } 266 267 func TestHeapWithRecorder(t *testing.T) { 268 metricRecorder := new(testMetricRecorder) 269 h := NewWithRecorder(testHeapObjectKeyFunc, compareInts, metricRecorder) 270 h.Add(mkHeapObj("foo", 10)) 271 h.Add(mkHeapObj("bar", 1)) 272 h.Add(mkHeapObj("baz", 100)) 273 h.Add(mkHeapObj("qux", 11)) 274 275 if *metricRecorder != 4 { 276 t.Errorf("expected count to be 4 but got %d", *metricRecorder) 277 } 278 if err := h.Delete(mkHeapObj("bar", 1)); err != nil { 279 t.Fatal(err) 280 } 281 if *metricRecorder != 3 { 282 t.Errorf("expected count to be 3 but got %d", *metricRecorder) 283 } 284 if _, err := h.Pop(); err != nil { 285 t.Fatal(err) 286 } 287 if *metricRecorder != 2 { 288 t.Errorf("expected count to be 2 but got %d", *metricRecorder) 289 } 290 291 h.metricRecorder.Clear() 292 if *metricRecorder != 0 { 293 t.Errorf("expected count to be 0 but got %d", *metricRecorder) 294 } 295 }